题目大概说有一棵树要给结点染色0或1,要求所有度为1的结点一半是0一半是1,然后问怎么染色,使两端点颜色不一样的边最少。
- dp[0/1][u][x]表示以u结点为根的子树中u结点是0/1色 且其子树有x个结点染成1色 的最少边数
转移就是树上背包了。有点就是各个子树必须选,这种形式的树上背包之前做过,我的做法是用了tmp数组来更新最后再写入根的状态数组中,另外我特判了第一个子树的转移方式。。写得好像有点挫。。
另外根随便选一个度不为1的即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define MAXN 5500 6 7 struct Edge{ 8 int v,next; 9 }edge[MAXN<<1]; 10 int NE,head[MAXN]; 11 void addEdge(int u,int v){ 12 edge[NE].v=v; edge[NE].next=head[u]; 13 head[u]=NE++; 14 } 15 16 int leafcnt[MAXN]; 17 void getlc(int u,int fa){ 18 bool isleaf=1; 19 for(int i=head[u]; i!=-1; i=edge[i].next){ 20 int v=edge[i].v; 21 if(v==fa) continue; 22 getlc(v,u); 23 leafcnt[u]+=leafcnt[v]; 24 isleaf=0; 25 } 26 if(isleaf) leafcnt[u]=1; 27 } 28 29 int d[2][MAXN][MAXN]; 30 void dfs(int u,int fa){ 31 bool isfirst=1,isleaf=1; 32 for(int i=head[u]; i!=-1; i=edge[i].next){ 33 int v=edge[i].v; 34 if(v==fa) continue; 35 isleaf=0; 36 dfs(v,u); 37 if(isfirst){ 38 isfirst=0; 39 for(int j=0; j<=leafcnt[u]; ++j){ 40 d[0][u][j]=min(d[0][v][j],d[1][v][j]+1); 41 d[1][u][j]=min(d[1][v][j],d[0][v][j]+1); 42 } 43 }else{ 44 int tmp[2][MAXN]; 45 for(int j=0; j<=leafcnt[u]; ++j){ 46 tmp[0][j]=tmp[1][j]=1111111; 47 } 48 for(int j=leafcnt[u]; j>=0; --j){ 49 for(int k=0; k<=min(leafcnt[v],j); ++k){ 50 tmp[0][j]=min(tmp[0][j],d[0][u][j-k]+d[1][v][k]+1); 51 tmp[0][j]=min(tmp[0][j],d[0][u][j-k]+d[0][v][k]); 52 tmp[1][j]=min(tmp[1][j],d[1][u][j-k]+d[1][v][k]); 53 tmp[1][j]=min(tmp[1][j],d[1][u][j-k]+d[0][v][k]+1); 54 } 55 } 56 for(int j=0; j<=leafcnt[u]; ++j){ 57 d[0][u][j]=tmp[0][j]; 58 d[1][u][j]=tmp[1][j]; 59 } 60 } 61 } 62 if(isleaf){ 63 d[0][u][0]=0; 64 d[1][u][1]=0; 65 } 66 } 67 68 int deg[MAXN]; 69 int main(){ 70 int n; 71 scanf("%d",&n); 72 memset(head,-1,sizeof(head)); 73 int a,b; 74 for(int i=1; i<n; ++i){ 75 scanf("%d%d",&a,&b); 76 addEdge(a,b); 77 addEdge(b,a); 78 ++deg[a]; ++deg[b]; 79 } 80 int root; 81 for(int i=1; i<=n; ++i){ 82 if(deg[i]!=1){ 83 root=i; 84 break; 85 } 86 } 87 getlc(root,root); 88 for(int i=1; i<=n; ++i){ 89 for(int j=0; j<=n; ++j){ 90 d[0][i][j]=d[1][i][j]=1111111; 91 } 92 } 93 dfs(root,root); 94 printf("%d",min(d[0][root][leafcnt[root]/2],d[1][root][leafcnt[root]/2])); 95 return 0; 96 }