标签:
/*
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;
}
标签:
原文地址:http://www.cnblogs.com/xuejianye/p/5662759.html