標籤:
F. Zublicanes and Mumocrates 樹形dp
題意給了一棵樹 要求使得這棵樹所有的節點分為兩個陣營,其中葉子節點要均分,求最少的兩個陣營相鄰, 也就是求 最少的邊使得 這些邊兩頭陣營不同
dp[cur][i][j] 表示當cur為i陣營的時候 有j個和i同陣營的方案
dp[cur][i][j+k] = min{dp[to][i^1][j=(葉子個數-d)]+dp[cur][i][k]+1,dp[to][i][j]+dp[cur][i][k]}
cnt為葉子節點的個數 最後答案是 min{ dp[root][0][cnt/2] ,dp[root][1][cnt/2]}
#include <algorithm>#include <string.h>#include <cstdio>#include <iostream>using namespace std;const int maxn=5005;int H[maxn],to[maxn*2],nx[maxn*2],numofE;void add(int u, int v){ numofE++; to[numofE]=v; nx[numofE]=H[u]; H[u]=numofE;}int dp[maxn][2][maxn];int dp2[2][maxn],sz[maxn];int d[maxn];void dfs(int cur ,int per){ if(d[cur]==1){ sz[cur]=1; dp[cur][0][1]=dp[cur][1][1]=0; return ; } dp[cur][0][0]=dp[cur][1][0]=0; for(int i=H[cur]; i ; i=nx[i]) { int tto = to[i]; if(tto==per)continue; dfs(tto,cur); for(int i=0; i<=sz[cur]; i++) for(int u=0; u<2; u++) { if( dp[cur][u][i] == -1 ) continue; for(int j=0; j<=sz[tto]; j++) for(int v=0; v<2; v++) { if(dp[tto][v][j]==-1)continue; if(u==v) { if(dp2[u][i+j]==-1) { int k=dp[cur][u][i]+dp[tto][v][j]; dp2[u][i+j] = k; }else { int k=min(dp[cur][u][i]+dp[tto][v][j],dp2[u][i+j]); dp2[u][i+j]=k; } }else { int nu=sz[tto]; if(dp2[u][i+nu-j]==-1) { int k=dp[cur][u][i]+dp[tto][v][j]+1; dp2[u][i+nu-j]=k; } else { int k=min(dp[cur][u][i]+dp[tto][v][j]+1,dp2[u][i+nu-j]); dp2[u][i+nu-j]=k; } } } } sz[cur]+=sz[tto]; for(int i=0; i<=sz[cur]; i++) for(int j=0; j<2; j++) { dp[cur][j][i]=dp2[j][i]; dp2[j][i]=-1; } }}int main(){ int n; while(scanf("%d",&n)==1) { memset(d,0,sizeof(d)); memset(dp,-1,sizeof(dp)); memset(sz,0,sizeof(sz)); memset(dp2,-1,sizeof(dp2)); memset(H,0,sizeof(H)); numofE=0; for(int i=1; i<n; i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); d[a]++;d[b]++; } if(n==2){ printf("%d\n",1); continue; } int root; int cnt=0; for(int i=1; i<=n; i++){ if(d[i]==1)cnt++; else root=i; } dfs(root,-1); printf("%d\n",min(dp[root][0][cnt/2],dp[root][1][cnt/2])); } return 0;}/*61 22 52 33 43 6*/View Code
Codeforces Round #322 (Div. 2)