标签:
题目链接:点击打开链接
题目描述:给定一棵树,从中选取尽量少的点使每个点要么被选中,要么和被选中的点直接相连?
解题思路:树上的最小支配集,树形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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
poj3659 Cell Phone Network(最小支配集-树形dp)
标签:
原文地址:http://blog.csdn.net/mengxingyuanlove/article/details/48001645