您的位置:首页 > 其它

POJ 3659 Cell Phone Network(树形DP)

2016-03-13 22:43 477 查看
Description

给出一棵点数为n的树,求这棵树的最小点覆盖

Input

第一行为一整数n表示树的点数,之后n-1行每行两个整数a和b表示树上a和b之间有一条边

Output

输出这棵树的最小点覆盖

Sample Input

5

1 3

5 2

4 3

3 5

Sample Output

2

Solution

dp[i][0]表示i属于支配集,并且以i为根的子树都被覆盖的情况下支配集的最少点数

dp[i][1]表示i不属于支配集,且以i为根的子树都被覆盖,且i被其中不少于一个子节点覆盖的情况下支配集的最少点数

dp[i][2]表示i不属于支配集,且以i为根的子树都被覆盖,且i没被子节点覆盖的情况下支配集的最少点数

dp[i][0]=1+sum(min(dp[u][0],dp[u][1],dp[u][2]))

dp[i][1]=INF i没有子节点

dp[i][1]=sum(min(dp[u][0],dp[u][1]))+inc i有子节点

inc=0若sum(min(dp[u][0],dp[u][1]))包含某个dp[u][0]

否则inc=min(dp[u][0]-dp[u][1])

dp[i][2]=sum(dp[u][1])

Code

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define maxn 11111
#define INF 0x3f3f3f3f
typedef long long ll;
struct Edge
{
int to,next;
}edge[2*maxn];
int n,head[maxn],tot;
int dp[maxn][3];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
for(int i=0;i<maxn;i++)dp[i][1]=INF;
}
void add(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void DP(int u,int fa)
{
dp[u][0]=1,dp[u][2]=0;
int sum=0,inc=INF,flag=0;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa)continue;
DP(v,u);
dp[u][0]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
if(dp[v][0]<=dp[v][1])
sum+=dp[v][0],flag=1;
else sum+=dp[v][1],inc=min(inc,dp[v][0]-dp[v][1]);
if(dp[v][1]!=INF&&dp[u][2]!=INF)dp[u][2]+=dp[v][1];
else dp[u][2]=INF;
}
if(inc!=INF&&!flag)dp[u][1]=INF;
else
{
dp[u][1]=sum;
if(!flag)dp[u][1]+=inc;
}
}
int main()
{
while(~scanf("%d",&n))
{
init();
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
DP(1,1);
int ans=min(dp[1][0],dp[1][1]);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: