zoukankan      html  css  js  c++  java
  • Codeforces 581F Zublicanes and Mumocrates(树形DP)

    题目大概说有一棵树要给结点染色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 }
  • 相关阅读:
    Effective Java 的笔记(二)
    设计模式系列 装饰模式
    一道多线程题目的解决方案
    Effective Java 的笔记(一)
    Java 并发编程实践
    【转】微博技术底层架构的实现
    Head First JavaScript 笔记
    JVM 学习笔记 类的加载和执行
    背包问题
    Oracle 序列号通过定时任务重置
  • 原文地址:https://www.cnblogs.com/WABoss/p/5687554.html
Copyright © 2011-2022 走看看