Codeforces Round #322 (Div. 2) F. Zublicanes and Mumocrates(树形dp,好题)

F. Zublicanes and Mumocrates
time limit per test
3 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

It's election time in Berland. The favorites are of course parties of zublicanes and mumocrates. The election campaigns of both parties include numerous demonstrations on n main squares of the capital of Berland. Each of the n squares certainly can have demonstrations of only one party, otherwise it could lead to riots. On the other hand, both parties have applied to host a huge number of demonstrations, so that on all squares demonstrations must be held. Now the capital management will distribute the area between the two parties.

Some pairs of squares are connected by (n - 1) bidirectional roads such that between any pair of squares there is a unique way to get from one square to another. Some squares are on the outskirts of the capital meaning that they are connected by a road with only one other square, such squares are called dead end squares.

The mayor of the capital instructed to distribute all the squares between the parties so that the dead end squares had the same number of demonstrations of the first and the second party. It is guaranteed that the number of dead end squares of the city is even.

To prevent possible conflicts between the zublicanes and the mumocrates it was decided to minimize the number of roads connecting the squares with the distinct parties. You, as a developer of the department of distributing squares, should determine this smallest number.

Input

The first line of the input contains a single integer n (2 ≤ n ≤ 5000) — the number of squares in the capital of Berland.

Next n - 1 lines contain the pairs of integers x, y (1 ≤ x, y ≤ n, x ≠ y) — the numbers of the squares connected by the road. All squares are numbered with integers from 1 to n. It is guaranteed that the number of dead end squares of the city is even.

Output

Print a single number — the minimum number of roads connecting the squares with demonstrations of different parties.

Examples
input
8
1 4
2 4
3 4
6 5
7 5
8 5
4 5
output
1
input
5
1 2
1 3
1 4
1 5
output
2

题意:

给出一棵n个节点的树,将树的节点染成黑白两种颜色,要求黑色叶子节点数目等于白色叶子节点数目

(保证偶数个叶子),求满足染色条件下连接不同色节点的最小边数

输入第一行为 n ,2 <= n <= 5000

接下来n-1行表示n-1条边


题解:

先特判n=2,否则选一个非叶节点作为根,
记dp[u][i][0/1]以u为根的子树中有i个叶子节点标为1且u标为0/1时该子树中的0-1边的个数最小值,
对于节点u,如果u是叶子,那么dp[u][0][0]=dp[u][1][1]=0,
否则枚举u的儿子v,枚举v标为0/1,再枚举v中标为0的叶子节点个数进行转移,
复杂度看上去是O(n^3),
但是如果在枚举标为0的叶子节点个数时只枚举到子树大小(或者枚举到子树中叶子节点的个数),
每加入一个子树v,枚举量是[u的已经枚举过的儿子v的子树大小之和]*[v子树大小],
可以证明复杂度是O(n^2)

quailty代码链接

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;
const ll mod=1000000007;
const int maxn=5000+5;
int head[maxn];
struct edge
{
    int from,to,next;
}e[maxn*2];   //
int tol=0;
void add(int u,int v)
{
    e[++tol].to=v,e[tol].next=head[u],head[u]=tol;
}
int deg[maxn];
int d[maxn][maxn][2];   //d[i][k][0/1]表示以i为根的树,有k个标记为1的点,当前根节点i标为0/1时最少的0-1边数
int dfs(int u,int f)        //函数返回叶子结点总数
{
    int tot=0,flag=1;
    d[u][0][0]=0;         //初始化,当u不是叶子结点时的初始化
    d[u][0][1]=0;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==f) continue;
        flag=0;
        int now=dfs(v,u);
        tot+=now;
        for(int i=tot;i>=0;i--)   //注意此处tot是递减的,有点像背包时滚动数组,要利用前面的结果
        {
            int mx[2]={inf,inf};
            for(int j=0;j<=min(now,i);j++)
            {
                mx[0]=min(mx[0],min(d[u][i-j][0]+d[v][j][0],d[u][i-j][0]+d[v][j][1]+1));
                //不能写成d[u][i][0]=min(d[u][i][0],min(d[u][i-j][0]+d[v][j][0],d[u][i-j][0]+d[v][j][1]+1))因为
                //先前的d[u][i][0]不包括以v为根的子树
                mx[1]=min(mx[1],min(d[u][i-j][1]+d[v][j][0]+1,d[u][i-j][1]+d[v][j][1]));
            }
            d[u][i][0]=mx[0],d[u][i][1]=mx[1];
        }
    }
    if(flag)
    {
        d[u][0][0]=d[u][1][1]=0;
        d[u][0][1]=inf;
        return 1;
    }
    else return tot;
    
}
int main()
{
    int n;
    scanf("%d",&n);
    rep(i,1,n)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
        deg[a]++,deg[b]++;
    }
    int root=-1;
    rep(i,1,n+1) if(deg[i]>1) root=i;
    rep(i,0,maxn) rep(j,0,maxn) rep(k,0,2) d[i][j][k]=inf;
    int sum=dfs(root,-1);
    printf("%d\n",min(d[root][sum/2][0],d[root][sum/2][1]));
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值