POJ 3659 Cell Phone Network【最小支配集】

题意:有以个 有 N 个节点的树形地图,问在这些顶点上最少建多少个电话杆,可以使得所有顶点被覆盖到,一个节点如果建立了电话杆,那么和它直接相连的顶点也会被覆盖到。

分析:用最少的点覆盖所有的点,即为求最少支配集。  可以用树形DP。

       ①  dp[r][0] += min(dp[i][0],dp[i][1],dp[i][2])    dp[r][0]表示在自 r 顶点自身建, 以 r 为根节点的树所需要的最少覆盖数。
       ②  dp[r][1] += min(dp[i][0],dp[i][1])                dp[r][1]表示在r 的子节点建,     以 r 为根节点的树所需要的最少覆盖数。
       ③  dp[r][2] += min(dp[i][0],dp[i][1])                dp[r][2]表示在r 的父节点建,     以 r 为根节点的数所需要的最少覆盖数。

       其中第 ② 个有 特殊情况需要考虑,即如果每次 min () 取得都是dp[i][1]的话,即 r 所有的子节点的都没有建电话杆的话,这样得出的结果就会有误差,可以在其中记录最小

       的dp[i][0]  值和其对应的 dp[i][1] 值,最后在这个 i 上建电话杆,就能保证自己被覆盖到,且用的电话杆最少, 这时dp[r][1]+=dp[i][0]-dp[i][1] 即可。

#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
int min(int a,int b)
{ return a<b?a:b; }
#define maxn 100005
#define INF 0x1f1f1f1f
struct node
{
    int to;
    int next;
}e[1000000];
int tot;
int head[maxn];
int dp[maxn][3];
void add(int s,int u)
{
    e[tot].to=u;
    e[tot].next=head[s];
    head[s]=tot++;
}
// dp[r][0] = min(dp[i][0],dp[i][1],dp[i][2])自身建
// dp[r][1] = min(dp[i][0],dp[i][1]) 子节点建
// dp[r][2] = min(dp[i][0],dp[i][1]) 父节点建
int n;
int v[maxn];
void dfs(int r)
{
    v[r]=1;
    int i,k;
    int flag=1,ff=1,mi=INF,t;
    dp[r][0]=1;
    for(i=head[r];i;i=e[i].next)
    {
        k=e[i].to;
        if(!v[k])
        {
            flag=0;
            dfs(k);
            dp[r][0]+=min(dp[k][0],min(dp[k][1],dp[k][2]));
            if(dp[k][1]>=dp[k][0])
            {
                ff=0;
                dp[r][1]+=dp[k][0];
            }
            else 
            {
                dp[r][1]+=dp[k][1];
                if(dp[k][0]<mi)
                {
                    mi=dp[k][0];
                    t=dp[k][1];
                }
            }
            dp[r][2]+=min(dp[k][0],dp[k][1]);
        }
    }
    if(ff)
        dp[r][1]+=mi-t;
    if(flag)
    {
        dp[r][0]=1;
        dp[r][1]=INF;
        dp[r][2]=0;
    }
}
int main()
{
    int a,b,i;
    while(scanf("%d",&n)!=EOF)
    {
        tot=1;
        clr(v);
        clr(dp);
        clr(head);
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }
        if(n==1)
        {
            printf("1\n");
            continue;
        }
        dfs(1);
        printf("%d\n",min(dp[1][0],dp[1][1]));
    }
    return 0;
}

 

posted @ 2012-08-06 10:03  'wind  阅读(942)  评论(0编辑  收藏  举报