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.
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.
Print a single number — the minimum number of roads connecting the squares with demonstrations of different parties.
8 1 4 2 4 3 4 6 5 7 5 8 5 4 5
1
5 1 2 1 3 1 4 1 5
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)
#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;
}