码迷,mamicode.com
首页 > 其他好文 > 详细

poj3659

时间:2016-07-12 11:56:54      阅读:124      评论:0      收藏:0      [点我收藏+]

标签:

/*
poj3659
树的最小支配集
树状DP
by xjy*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=10000+100;
struct node//链式前向星存图
{
    int to;
    int next;
};
node edge[2*maxn];//因为无向,所以同一条边会存两次
bool vis[maxn];
int head[maxn];
int dp[maxn][3];//状态,对于树上的任意一个点,其合法状态有三种,被自身覆盖,被父节点覆盖,被子节点覆盖
int n;
int tot;
const int inf=0xfffff;
void add(int x,int y)
{
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot++;//记录该点这次出现的边的位置
}
void dfs(int nod)
{
    bool flag=true;//在对dp[nod][1]的处理上要用到
    dp[nod][0]=1,dp[nod][1]=dp[nod][2]=0;//初始化
    vis[nod]=true;
    int Min=inf;
    int v;
    for(int i=head[nod];i!=-1;i=edge[nod].next)
    {
        v=edge[i].to;
        if(!vis[v])
        {
            dfs(v);
            dp[nod][0]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
            dp[nod][2]+=min(dp[v][0],dp[v][1]);
            if(dp[v][0]<=dp[v][1])
            {
                flag=false;
                dp[nod][1]+=dp[v][0];
            }
            else
            {
                dp[nod][1]+=dp[v][1];
                Min=min(Min,dp[v][0]-dp[v][1]);
            }
        }
    }
    if(flag) //所有子节点都没有放置,不合题意,选择最优的进行放置
        dp[nod][1]+=Min;//对于叶子节点,dp[i][1]=inf:
}
void init()
{
    int a,b;
    memset(head,-1,sizeof(head));
    memset(vis,false,sizeof(vis));
    tot=1;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
}
int main()
{
     while(scanf("%d",&n)!=EOF)
     {
         init();
         dfs(2);
         printf("%d\n",min(dp[2][0],dp[2][1]));//选1作为整个树的根节点,不可能出现其被其父节点覆盖的情况
     }
    return 0;
}

poj3659

标签:

原文地址:http://www.cnblogs.com/xuejianye/p/5662759.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!