1907: 树的路径覆盖
Time Limit: 5 Sec
Memory Limit: 259 MB
Submit: 661
Solved: 299
Description
Input
Output
Sample Input
1
7
1 2
2 3
2 4
4 6
5 6
6 7
7
1 2
2 3
2 4
4 6
5 6
6 7
Sample Output
3
HINT
题解:
对于每个节点x:
f[x][0]表示没有选择x点与父节点相连的路径时,其子树的最小路径覆盖数;
f[x][1]表示选择了x点与父节点相连的路径时,其子树最小路径覆盖数;
每个块的形态只有两种:“倒v”,或呈链状。
对于“倒v”:我们只需要计算在该点的f[x][0],为子树中的块数之和-1;
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define clear(A) memset(A,0,sizeof(A))
using namespace std;
const int M=40005;
const int N=10005;
int T,n,x,y;
int to[M],nxt[M],lj[N],cnt;
void add(int f,int t)
{
cnt++;
to[cnt]=t;
nxt[cnt]=lj[f];
lj[f]=cnt;
}
int s[N],fa[N],f[N][2];
void dfs(int x)
{
bool flag=false;
int tmp=0;
f[x][0]=f[x][1]=1;
for(int i=lj[x];i;i=nxt[i])
if(to[i]!=fa[x])
{
fa[to[i]]=x;
dfs(to[i]);
f[x][0]=min(f[x][0]+f[to[i]][0],f[x][1]+f[to[i]][1]-1);
f[x][1]=min(f[x][1]+f[to[i]][0],tmp+f[to[i]][1]);
tmp+=f[to[i]][0];
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
cnt=0;
clear(lj);
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(1);
printf("%d\n",min(f[1][0],f[1][1]));
}
}