您的位置:首页 > 其它

poj3659 Cell Phone Network(最小支配集-树形dp)

2015-08-26 12:21 531 查看
题目链接:点击打开链接

题目描述:给定一棵树,从中选取尽量少的点使每个点要么被选中,要么和被选中的点直接相连?

解题思路:树上的最小支配集,树形dp

dp[i][0]:选中i作为支配集

dp[i][1]:不选i作为支配集,但其子节点覆盖了i

dp[i][2]:不选i作为支配集,而且其子节点没有覆盖i

代码:

#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <iostream>
#define MAXN 10010
#define INF 1e9+7
using namespace std;
int head[MAXN],tol;
struct Edge{
int v,next;
}edge[MAXN*2];
void addEdge(int u,int v){
edge[tol].v=v;edge[tol].next=head[u];head[u]=tol++;
edge[tol].v=u;edge[tol].next=head[v];head[v]=tol++;
}
int min(int a,int b){
return a<b?a:b;
}
int dp[MAXN][3];
int n;
void DP(int u,int p){
dp[u][2]=0;
dp[u][0]=1;
int sum=0,inc=INF;
int k,to;
bool s=false;
for(k=head[u];k!=-1;k=edge[k].next){
to=edge[k].v;
if(to==p) continue;
DP(to,u);
dp[u][0]+=min(dp[to][0],min(dp[to][1],dp[to][2]));
if(dp[to][0]<=dp[to][1]){
sum+=dp[to][0];
s=true;
}
else
{
sum+=dp[to][1];
inc=min(inc,dp[to][0]-dp[to][1]);
}
if(dp[to][1]!=INF&&dp[u][2]!=INF) dp[u][2]+=dp[to][1];
else dp[u][2]=INF;
}
if(inc==INF&&!s) dp[u][1]=INF;
else{
dp[u][1]=sum;
if(!s) dp[u][1]+=inc;
}
}
int main(){
while(scanf("%d",&n)!=EOF){
tol=0;memset(head,-1,sizeof(head));
int u,v;
for(int i=0;i<n-1;++i){scanf("%d%d",&u,&v);addEdge(u,v);}
DP(1,1);
printf("%d\n",min(min(dp[1][0],dp[1][1]),dp[1][2]+1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: