[HAOI2015]树上染色
树形DP题
一开始真难想。
关键思路在于统计每条边的贡献。
设 f[u][j]表示以u为根的子树 有j个黑点,对答案的贡献。
递推式子比较好写:f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]+val)
val=ed[i].w*(k*(m-k)+(siz[v]-k)*(n-m-siz[v]+k)) ————记得开long long
val表示该边左右的黑点相连的方案数+白点相连的方案数。
交了坐等AC………………………………80分!!!!!
原因竟是…………………f数组要赋初值为-1!
百思不得其解,去问郭老师。
gls认真讲题(真帅):赋初值为-1表示该状态不合法。如果不赋初值为-1,会导致某一个状态是由一个不合法的状态转移来的,(例如一个size为4的子树有6个黑节点)。dfs过程中,f[x][0]=f[x][1]=0表示该状态为合法的。状态转移时判断一下 f[x][j-k]!=-1 就行了。
嗯,真棒,A了。
以下是代码:
#include<bits/stdc++.h> #define ll long long #define RE register using namespace std; const int maxn=2100; inline int R(){ RE char b=getchar();int x=0,t=1; while(b<'0'||b>'9'){if(b=='-') t=-1;b=getchar();} while(b>='0'&&b<='9') {x=(x<<3)+(x<<1)+b-'0';b=getchar();} return x*t; } struct Edge{ int nxt,to,w; }ed[maxn<<1]; int head[maxn],ecnt; void addedge(int f,int to,int w){ ed[++ecnt].to=to; ed[ecnt].w=w; ed[ecnt].nxt=head[f]; head[f]=ecnt; } int n,m; int siz[maxn]; ll f[maxn][maxn]; void dfs(int x,int fa){ siz[x]=1; f[x][0]=f[x][1]=0; for(int i=head[x];i;i=ed[i].nxt){ int v=ed[i].to; if(v==fa) continue; dfs(v,x); siz[x]+=siz[v]; for(int j=min(m,siz[x]);j>=0;j--) for(int k=0;k<=min(j,siz[v]);k++) if(f[x][j-k]!=-1) f[x][j]=max(f[x][j],f[x][j-k]+f[v][k]+1ll*ed[i].w*(1ll*k*(m-k)+1ll*(siz[v]-k)*(n-m-siz[v]+k))); } } int main(){ n=R(),m=R(); memset(f,-1,sizeof f); for(int i=1,a,b,c;i<=n-1;i++){ a=R(),b=R(),c=R(); addedge(a,b,c); addedge(b,a,c); } dfs(1,0); printf("%lld",f[1][m]); return 0; }