1. 程式人生 > >BZOJ 4033 [HAOI2015]樹上染色

BZOJ 4033 [HAOI2015]樹上染色

tor isp 背包 pri math class 分享 bsp [1]

樹DP 。

考慮每條邊對答案的貢獻是邊兩邊的黑點數乘積加白點數乘積乘以邊長。所以我們只要知道一個點的某個子樹中的黑點數就可以算它到子樹這條邊的貢獻。

就可以樹上跑背包。

註意一是不要隨便只開單向邊(會GG),二是DP初值設為-1,dp[x][0].dp[x][1]初始為0,這樣不會考慮不存在的狀態。

技術分享
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include
<vector> typedef long long LL; using namespace std; const int maxn=2005; int n,k,x,y,z,fir[maxn],nxt [maxn*2],to[maxn*2],ecnt,sz[maxn]; LL val[maxn*2],dp[maxn][maxn]; void add(int u,int v,LL w) { nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w; nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w; }
void DFS(int x,int f) { sz[x]=1; for(int i=fir[x];i;i=nxt[i]) if(to[i]!=f){ DFS(to[i],x); sz[x]+=sz[to[i]]; } } void dfs(int x,int f) { memset(dp[x],-1,sizeof(dp[x])); dp[x][0]=dp[x][1]=0; for(int i=fir[x];i;i=nxt[i]) if(to[i]!=f){ dfs(to[i],x); int u=to[i],up=min(k,sz[x]);
for(int v=up;v>=0;v--) { for(int j=0;j<=sz[u]&&j<=v;j++) if(dp[x][v-j]!=-1){ dp[x][v]=max(dp[x][v],dp[x][v-j]+dp[u][j]+(LL)(j*(k-j)+(sz[u]-j)*(n-sz[u]-k+j))*val[i]); } } } } int main() { //freopen(".in","r",stdin); //freopen(".out","w",stdout); scanf("%d%d",&n,&k); for(int i=1;i<n;i++) { scanf("%d%d%lld",&x,&y,&z); add(x,y,z); } DFS(1,0); dfs(1,0); printf("%lld\n",dp[1][k]); return 0; }
View Code

BZOJ 4033 [HAOI2015]樹上染色