求最大独立集+判断唯一性----树形dp

求最大独立集----树形dp
亲爱的选手,

我将在我的别墅在Hali-Bula举行一个聚会,以庆祝我从业连管退休。我希望我能邀请我所有的同事,但是想象一下,当一个员工在客人中找到他的老板时,他会怎样享受一个聚会!所以,我决定不邀请员工和他/她的老板。在业连管的组织层次是这样的,没有人有超过一个老板,而且只有一个员工没有老板(大老板)!我可以请你写一个程序来确定客人的最大数量,这样当他/她的老板也被邀请的时候,就不会有员工被邀请了吗?我已经附上了员工名单和业连管的组织等级。

最好,
-布莱恩·班尼特

如果你的节目能说明如果我选择邀请有这种条件的客人的最大数量,那么这个名单是否是唯一确定的,我将不胜感激。

输入

输入由多个测试用例组成。每个测试用例都由一个包含整数的行开始。n(1≤)n(≤200),业连管的雇员人数。下一行只包含“大老板”的名称。以下每一项n-一行包括雇员的姓名和老板的姓名。所有的名字都是至少一个字串,最多100个字母,用空格隔开。每个测试用例的最后一行包含一个0。

输出量

对于每个测试用例,编写一行,其中包含一个数字,指示根据所需条件可以邀请的最大来宾数,以及一个单词“是”或“否”,这取决于在这种情况下来宾列表是否是唯一的。

样本输入

6
Jason
Jack Jason
Joe Jack
Jill Jason
John Jack
Jim Jill
2
Ming
Cho Ming
0
样本输出

4 Yes
1 No

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
vector<ll> p[201];
//dp[i][0]表示不取i节点
//dp[i][1]表示取i节点
//dup[i][0]表示不取i节点是否唯一,等于0表示不唯一,等于1表示唯一
//dup[i][1]表示取i节点是否唯一,,,,,, 
ll dp[201][2],dup[201][2]; 
map<string,ll> mp;
//在一棵树中找不相邻的节点,求最大的数量,并判断方案是否唯一
//找最大独立集问题 
 
void dfs(ll root){
    dp[root][1]=1;
    dp[root][0]=0;
    dup[root][0]=1;
    dup[root][1]=1;
    ll len=p[root].size();
    for(ll j=0;j<len;j++){
        ll u=p[root][j];
        dfs(u);
        dp[root][0]+=max(dp[u][0],dp[u][1]);
        dp[root][1]+=dp[u][0];
        //判唯一性:根据子节点的情况决定 
        //不选root节点的唯一性判断 
        if(dp[u][0]>dp[u][1]&&dup[u][0]==0){
            dup[root][0]=0;
        }
        else if(dp[u][1]>dp[u][0]&&dup[u][1]==0){
            dup[root][0]=0;
        }
        else if(dp[u][0]==dp[u][1]){
            dup[root][0]=0;
        }
        //选root节点的唯一性判断 
        if(dup[u][0]==0){
            dup[root][1]=0;
        }
    }
}
 
 
int main(){
    ll n;
    while(cin>>n&&n){
        for(ll i=1;i<=200;i++){
            p[i].clear();
        }
        mp.clear();
        string a,b;
        cin>>a;
        ll cnt=1;
        if(!mp[a]){
            mp[a]=cnt++;
        }
        for(ll i=1;i<n;i++){
            cin>>a>>b;
            if(!mp[a]){
                mp[a]=cnt++;
            }
            if(!mp[b]){
                mp[b]=cnt++;
            }
            p[mp[b]].push_back(mp[a]);
        }
        memset(dp,0,sizeof(dp));
        memset(dup,0,sizeof(dup));
        dfs(1);
        //求最优方案:max(dp[1][0],dp[1][1]); 
        if(dp[1][0]>dp[1][1]&&dup[1][0]==1){
            cout<<dp[1][0]<<" Yes"<<endl;
        }
        else if(dp[1][1]>dp[1][0]&&dup[1][1]==1){
            cout<<dp[1][1]<<" Yes"<<endl;
        }
        else cout<<max(dp[1][1],dp[1][0])<<" No"<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值