POJ 3659 Cell Phone Network(树形DP)

来源:互联网 发布:php jquery ajax登录 编辑:程序博客网 时间:2024/04/30 16:47

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 0x3f3f3f3ftypedef 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;}
0 0
原创粉丝点击