Codeforces Round #322 (Div. 2) F

来源:互联网 发布:origin9.1绘图软件 编辑:程序博客网 时间:2024/05/22 12:55

题意:给出一棵树,将这棵树分为两个集合,要求两个集合中度为一的节点的数量相同(普通的节点的个数可以不同)。如果一条边连接了两个不同的集合,那么就称为“冲突边”,问“冲突边”最小为多少。

思路:很明显是树形dp,比赛的时候想dp(i,j,k,c)表示到第i个节点,A集合有j个度为一的节点的个数,B有j个度为一的节点的个数,当前点为属于C集合,然后空间时间都爆掉了,然后乱搞,没敲完。赛后看的别人代码,发现其实可以省掉一个K或J,因为最终要求是J=K,所以中间的各种情况是多少都没有用,只要在最后的时候找J=ALL/2的个数就好。这样就能做了。


dp[i][j][k]表示到了第i个节点,染为0的叶子节点的个数为j,且当前节点颜色为k时最少的冲突边的个数

然后转移的时候,需要知道用当前节点下面的所有子树能拼出什么情况,就可以用两个数组来维护,这里请看代码。。。

最后输出当前点分属两个集合时较小的一个就好

不过我的代码效率略低= =

代码:

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int maxn = 5010;const int inf = 0x3f3f3f3f;struct Side{    int v,next;}side[maxn*2];int node[maxn],top;void add_side(int u,int v){    side[top] = (Side){v,node[u]};    node[u] = top ++;}int n;int in[maxn];int dp[maxn][maxn][2];//dangqianjiedian , ran wei 0 de ge shu ,dangqina dian ran seint tmp[maxn][maxn];int dfs(int now,int fa){    if(in[now] == 1){        dp[now][1][0] = 0;        dp[now][0][1] = 0;        return 1;    }    int tot = 0;    dp[now][0][0] = 0;    dp[now][0][1] = 0;    for(int i = node[now];i != -1;i = side[i].next){        int v = side[i].v;        if(v != fa){            int num = dfs(v,now);            for(int i = 0;i <= tot;i ++){                for(int j = 0;j < 2;j ++){                    tmp[i][j] = dp[now][i][j];                    dp[now][i][j] = inf;                }            }// fu chu zhi            for(int a = 0;a < 2;a ++){                for(int i = tot;i >= 0;i --){                    if(tmp[i][a] == inf)continue;                    for(int b = 0;b < 2;b ++){                        for(int j = 0;j <= num;j ++){                            if(dp[v][j][b] != inf){                                dp[now][i+j][a] = min(dp[now][i+j][a],tmp[i][a] + dp[v][j][b] + (a^b));                            }                        }                    }                }            }            tot += num;        }    }    return tot;}int main(){    while(cin>>n){        memset(node,-1,sizeof(node));        top = 0;        memset(in,0,sizeof(in));        for(int i = 0;i < n-1;i ++){            int a,b;            scanf("%d%d",&a,&b);            add_side(a,b);            add_side(b,a);            in[a] ++;in[b] ++;        }        memset(dp,inf,sizeof(dp));        int in1 = 0;        for(int i = 1;i <= n;i ++){            if(in[i] == 1)in1 ++;        }        for(int i = 1;i <= n;i ++){            if(in[i] != 1){                dfs(i,0);                cout<<min(dp[i][in1/2][0],dp[i][in1/2][1])<<endl;                break;            }        }    }    return 0;}


0 0
原创粉丝点击