poj3342

来源:互联网 发布:office visio软件下载 编辑:程序博客网 时间:2024/04/28 02:47

树形dp,相当于求最大独立子集!!!麻烦在于判断唯一性!!!

 

#include<iostream>
#include<stdio.h>
#include<map>
#include<vector>
#include<string>
using namespace std;
int n;
vector<int> son[205];
int dp[205][2];
int num;
int treep(int k,int p)//k为节点标号;p为是否选的标志
    {//记忆化搜索
        int i,len,sum;
        if(dp[k][p]!=-1)
        {return dp[k][p];}//以被算过
        len=son[k].size();
        if(p){//k被选k的儿子全不能选
            sum=1;
            for(int i=0;i<len;i++) sum=sum+treep(son[k][i],0);
            dp[k][p]=sum;
            return sum;}
        else{//k不选k的儿子可选课不选
            sum=0;
            for(int i=0;i<len;i++) sum+=max(treep(son[k][i],0),treep(son[k][i],1));
            dp[k][p]=sum;
            return sum;
            }
        }
int check(){
 int i,j;//保证每一次选择都是唯一的!!!
 for(i=1;i<=n;i++)if(dp[i][0]>=dp[i][1])//若不选i<选i的情况;对于i一定不会相同
    {for(j=0;j<son[i].size();j++)
        if(dp[son[i][j]][1]==dp[son[i][j]][0])
            return 0;}
        return 1;
}

int main(){

    while(scanf("%d",&n)==1&&n){
        string s1,s2;
        int flag=1;
        for(int i=1;i<=n;i++) son[i].clear();
        for(int i=1;i<=n;i++) dp[i][0]=dp[i][1]=-1;//表示i点的dp值还没算过;
        cin>>s1;
        if(n==1) {cout<<"1 Yes"<<endl;continue;}
        num=0;
        map<string,int> m;
        m.clear();
        m[s1]=++num;//第一个节点编号为一
        for(int i=1;i<n;i++){
            cin>>s1>>s2;
        if(!m[s1]) m[s1]=++num;
        if(!m[s2]) m[s2]=++num;
        son[m[s2]].push_back(m[s1]);//建立树;
        }
        for(int i=1;i<=n;i++)//节点最大编号为n
            if(son[i].size()==0){//找道叶子节点!!!
                dp[i][0]=0;dp[i][1]=1;}//被选则为1不选则为0;
        int ans1=treep(1,0);
        int ans2=treep(1,1);
        cout<<max(ans1,ans2);

        if(ans1==ans2) flag=0;
        if(flag) flag=check();//判断是否唯一
        if(flag)
            cout<<" Yes"<<endl;
        else
            cout<<" No"<<endl;

    }

    return 0;}

 

原创粉丝点击