Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 4416 | Accepted: 1562 |
Description
Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires him to set up cell phone towers on his N (1 ≤ N ≤ 10,000) pastures (conveniently numbered 1..N) so they can all communicate.
Exactly N-1 pairs of pastures are adjacent, and for any two pastures A and B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B) there is a sequence of adjacent pastures such that A is the first pasture in the sequence and B is the last. Farmer John can only place cell phone towers in the pastures, and each tower has enough range to provide service to the pasture it is on and all pastures adjacent to the pasture with the cell tower.
Help him determine the minimum number of towers he must install to provide cell phone service to each pasture.
Input
* Line 1: A single integer: N
* Lines 2..N: Each line specifies a pair of adjacent pastures with two space-separated integers: A and B
Output
* Line 1: A single integer indicating the minimum number of towers to install
Sample Input
5 1 3 5 2 4 3 3 5
Sample Output
2
Source
/*算法思想:
给一棵树,选择最少的顶点使得整棵树被覆盖
树形dp
由于每个节点被覆盖的方式只有两种:被相邻节点覆盖和自己覆盖自己,那么,我们可以给每个节点三个状态:
f[i][0]:表示节点 i 被它的父亲覆盖,以 i 为根的子树需要覆盖的顶点的最少数量
f[i][1]:表示节点 i 自己覆盖自己,以 i 为根的子树需要覆盖的顶点的最少数量
f[i][2]:表示节点 i 被它的儿子覆盖,以 i 为根的子树需要覆盖的顶点的最少数量
那么就有一下状态转移方程:
1、f[i][0]+=min(f[i_son][1] , f[i_son][2])
2、f[i][1]+=min(f[i_son][0] , f[i_son][1] , f[i_son][2]) +1
3、f[i][2]+=min(f[i_son][1] , f[i_son][2])
对于第三个状态转移方程:当所有的 f[i_son][2]<f[i_son][1] 时,第 i 个节点实际上是没有被它的儿子覆盖
的。所以,我们要找一个儿子,用它来覆盖 i 节点;这种情况下,我们需要增加 f[i][2] 的值。增加的值就是
找 f[i_son][1]-f[i_son][2] 那么,用来覆盖节点 i 的这个儿子应该满足:f[i_son][1]-f[i_son][2] 最小。
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x7fffffff
using namespace std;
struct data
{
int st,en,next;
} edge[20005];
int f[20005][3],d[20005];
int head[20005],tot;
void add_edge(int st,int en) //加边
{
edge[tot].st=st;
edge[tot].en=en;
edge[tot].next=head[st];
head[st]=tot++;
}
void dfs(int u,int fa) //dfs过程
{
if(d[u]==1 && u!=1) //叶子节点
{
f[u][0]=0;
f[u][1]=1;
f[u][2]=INF;
return;
}
bool fg=true;
int Min=INF;
for(int i=head[u];i!=-1;i=edge[i].next)
{
if(edge[i].en==fa) continue; //树,排除重边
dfs(edge[i].en,u);
f[u][0]+=min(f[edge[i].en][1],f[edge[i].en][2]);
f[u][1]+=min(min(f[edge[i].en][0],f[edge[i].en][1]),f[edge[i].en][2]);
if(f[edge[i].en][1]<=f[edge[i].en][2])
{
f[u][2]+=f[edge[i].en][1];
fg=false;
}
else
{
f[u][2]+=f[edge[i].en][2];
Min=min(f[edge[i].en][1]-f[edge[i].en][2],Min); //找最小的需要添加的值
}
}
f[u][1]++;
if(fg) f[u][2]+=Min;
}
int main()
{
int n,a,b;
while(scanf("%d",&n)!=EOF)
{
memset(head,-1,sizeof(head));
tot=0;
memset(d,0,sizeof(d));
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
add_edge(a,b);
add_edge(b,a);
d[a]++;
d[b]++;
}
memset(f,0,sizeof(f));
dfs(1,0);
if(n!=1) printf("%d\n",min(f[1][1],f[1][2]));
else printf("1\n");
}
return 0;
}