Luogu4383 [八省联考2018]林克卡特树
作者:互联网
https://www.luogu.com.cn/problem/P4383
\(wqs\)二分/树型\(DP\)
可以看到,题目本质上要求的是取\(k+1\)条链,使其边权和最大
先打一个树型\(DP\)(够头疼的了)
\(dp_{i,j,0/1/2}\),\(i\)表示哪一个节点,\(j\)表示已经用了几条链了,\(0/1/2\)代表的是一个节点的度数,注意,当度数为\(1\)时,我们不计算该条链的贡献(因为可能与其他链拼接)
注意,一个点也可以作为一条链,我们直接初始化\(dp_{i,1,2}=0\),表示该点单独取
此外,\(dp_{i,0,0}=0\)(不取,显然),其他位置的权值都为\(-INF\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define N 600005
#define INF 12345678987654321
using namespace std;
int tot,head[N],nxt[N],d1[N],d2[N],n,k,x,y,z;
ll ans,dp[N >> 1][105][3],kz[105][3];
void add(int x,int y,int z)
{
tot++;
d1[tot]=y,d2[tot]=z;
nxt[tot]=head[x];
head[x]=tot;
}
void ckmx(ll &x,ll y)
{
if (x<y)
x=y;
}
void dfs(int u,int f)
{
for (int i=head[u];i;i=nxt[i])
{
int v=d1[i];
int cost=d2[i];
if (v==f)
continue;
dfs(v,u);
for (int t=0;t<=k;t++)
for (int q=0;q<3;q++)
kz[t][q]=dp[u][t][q];
for (int t=k;t>=0;t--)
{
for (int q=0;q<=t;q++)
{
ckmx(dp[u][t][0],dp[v][q][0]+kz[t-q][0]);
if (t>q)
ckmx(dp[u][t][0],dp[v][q][1]+kz[t-q-1][0]);
ckmx(dp[u][t][0],dp[v][q][2]+kz[t-q][0]);
ckmx(dp[u][t][1],dp[v][q][0]+kz[t-q][1]);
ckmx(dp[u][t][1],dp[v][q][0]+kz[t-q][0]+cost);
if (t>q)
ckmx(dp[u][t][1],dp[v][q][1]+kz[t-q-1][1]);
ckmx(dp[u][t][1],dp[v][q][1]+kz[t-q][0]+cost);
ckmx(dp[u][t][1],dp[v][q][2]+kz[t-q][1]);
ckmx(dp[u][t][2],dp[v][q][0]+kz[t-q][2]);
if (t>q)
ckmx(dp[u][t][2],dp[v][q][0]+kz[t-q-1][1]+cost);
if (t>q)
ckmx(dp[u][t][2],dp[v][q][1]+kz[t-q-1][2]);
if (t>q)
ckmx(dp[u][t][2],dp[v][q][1]+kz[t-q-1][1]+cost);
ckmx(dp[u][t][2],dp[v][q][2]+kz[t-q][2]);
}
}
}
}
int main()
{
scanf("%d%d",&n,&k),k++;
for (int i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
for (int i=0;i<=n;i++)
{
for (int j=0;j<=k;j++)
for (int t=0;t<3;t++)
dp[i][j][t]=-INF;
dp[i][0][0]=dp[i][1][2]=0;
}
dfs(1,0);
ans=max(dp[1][k][0],max(dp[1][k-1][1],dp[1][k][2]));
printf("%lld\n",ans);
return 0;
}
标签:八省,int,Luogu4383,tot,联考,cost,kz,ckmx,dp 来源: https://www.cnblogs.com/GK0328/p/13525084.html