poj 3342 树形DP

DP过程

注意:对于每个矛盾关系,从老板向员工连一条边

dp[i][0]表示不取i的最大值,可以由两个状态转移而来dp[i][0]+=sigma[ max(dp[j][0],dp[j][1])],j为儿子,即儿子取或不取都可以

dp[i][1]表示取i的最大值,初始值赋为1,那么儿子节点就不能取了,所以dp[i][1]=sigma(dp[j][0]);

 

 

判断方案是否唯一

 

观察状态转移的过程可知:dp[i][0]是由dp[j][0],dp[j][1]两个状态过来的,所以当dp[j][0]==dp[j][1]时,方案不唯一,即子节点选与不选都可以

但是注意前提是dp[i][0]更优与dp[i][1],即i这个节点肯定被选择了,否则状态就仅仅由dp[j][1]转移而来,不能判断不唯一。

View Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
using namespace std;
#define max(a,b) a>b?a:b
const int maxn = 201;
vector<int> edge[maxn];
int dp[210][2];
void dfs(int u,int p)
{
int i,j;
dp[u][1]=1;
dp[u][0]=0;
for(i=0;i<edge[u].size();i++)
{
int v=edge[u][i];
if(v==p) continue;
dfs(v,u);
dp[u][1]+=dp[v][0];
dp[u][0]+=max(dp[v][0],dp[v][1]);
}
}
int main(){
map<string,int> mm;
int n,i,tot;
char bos[110],a[110],b[110];
while(scanf("%d",&n),n)
{
tot=0;
for(i=0;i<=200;i++) edge[i].clear();
mm.clear();
scanf("%s",bos);mm[bos]=tot++;
for(i=0;i<n-1;i++)
{
scanf("%s%s",a,b);
if(mm.find(a)==mm.end()) mm[a]=tot++;
if(mm.find(b)==mm.end()) mm[b]=tot++;
edge[mm[b]].push_back(mm[a]);
}
dfs(0,0);bool flag=true;
for(i=0;i<n;i++)
{
flag=true;
if(dp[i][0]>dp[i][1])
{
for(int j=0;j<edge[i].size();j++)
{
if(dp[edge[i][j]][0]==dp[edge[i][j]][1])
{
flag=false;
break;
}
}
}
if(!flag) break;
}
printf("%d",max(dp[0][0],dp[0][1]));
if(dp[0][0]==dp[0][1]||!flag) printf(" No\n");
else printf(" Yes\n");
}
return 0;
}



posted @ 2012-03-08 19:22  Because Of You  Views(1009)  Comments(0Edit  收藏  举报