您的位置:首页 > 其它

【算法竞赛入门经典】树的最大独立集、树的唯一性问题 例题9-13 UVa1220

2018-03-08 08:53 686 查看

【算法竞赛入门经典】树的最大独立集、树的唯一性问题 例题9-13 UVa1220

【算法竞赛入门经典】树的最大独立集、树的唯一性问题 例题9-13 UVa1220
例题UVa12186

分析

样例实现代码

结果

例题UVa12186

Dear Contestant,

I’m going to have a party at my villa at Hali-Bula to celebrate my retirement from BCM. I wish I could invite all my co-workers, but imagine how an employee can enjoy a party when he finds his boss among the guests! So, I decide not to invite both an employee and his/her boss. The organizational hierarchy at BCM is such that nobody has more than one boss, and there is one and only one employee with no boss at all (the Big Boss)! Can I ask you to please write a program to determine the maximum number of guests so that no employee is invited when his/her boss is invited too? I’ve attached the list of employees and the organizational hierarchy of BCM.

Best, –Brian Bennett

P.S. I would be very grateful if your program can indicate whether the list of people is uniquely determined if I choose to invite the maximum number of guests with that condition.

Input

The input consists of multiple test cases. Each test case is started with a line containing an integer n (1 ≤ n ≤ 200), the number of BCM employees. The next line contains the name of the Big Boss only. Each of the following n−1 lines contains the name of an employee together with the name of his/her boss. All names are strings of at least one and at most 100 letters and are separated by blanks. The last line of each test case contains a single ‘0’.

Output

For each test case, write a single line containing a number indicating the maximum number of guests that can be invited according to the required condition, and a word ‘Yes’ or ‘No’, depending on whether the list of guests is unique in that case.

Sample Input

6

Jason

Jack Jason

Joe Jack

Jill Jason

John Jack

Jim Jill

2

Ming

Cho Ming

0

Sample Output

4 Yes

1 No

分析

首先显然字符串操作会很麻烦耗时,而且操作过程中和输出和字符串无关,不如给其编号。

其次,输入的同时,已经进行了建树(有根),即:每个节点的子节点是知道的。

此处用d[u][0]表示不选择节点u时,以u为根的子树的最大可选人数,那么d[u][1]则表示选择节点u的时候,以u为根的子树的最大可选人数。

同样的f[u][0]表示不选择节点u时,以u为根的子树的最大可选人数是否唯一,f[u][1]表示选择时的情况。

此时考虑状态转移方程:

1.选择节点u的时候,所有子节点必须不选
d[u][1]=sum(d[v][0])+1
考虑独立性:只有在任意一个子节点f[v][0]不唯一的时候,f[u][1]才会不唯一。

2.不选择节点u的时候,子节点可选可不选
d[u][0]=sum(max(d[v][0],d[v][1]))
考虑独立性:当d[v][0]和d[v][1]值相同的时候,选择哪一个都行,那么就不唯一了。若是选择的其中大的那个不唯一,那么f[u][0]也不唯一。

根据以上,本题涉及重复计算,所以要使用记忆化搜索。

根节点的判唯一方式也类似与子节点。

另外:本题使用的是递归而不是递推来做,究其原因是因为不能保证递推从子节点开始。若是输入时能获知节点层次,那么直接从下往上递推显然效率更高。

样例实现代码

#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
#define maxn 200+5
using namespace std;
int n,cnt;
int d[maxn][2];
bool f[maxn][2];
vector<int>sons[maxn];
map<string,int>dict;
int ID(string &s){
if(!dict.count(s))
dict[s]=cnt++;
return dict[s];
}
int dp(int n,int flag){
d
[flag]=flag;
f
[flag]=true;
for(int i=0;i<sons
.size();i++){
int v=sons
[i];
if(flag==1){
d
[1]+=dp(v,0);
if(!f[v][0])
f
[1]=false;
}
else{
d
[0]+=max(dp(v,0),dp(v,1));
if(d[v][0]==d[v][1])
f
[0]=false;
else if(d[v][0]>d[v][1]){
if(!f[v][0])
f
[0]=false;
}
else{
if(!f[v][1])
f
[0]=false;
}
}
}
return d
[flag];
}
int main(){
while(cin>>n&&n){
string s,boss;
for(int i=0;i<=n;i++)
sons[i].clear();
dict.clear();
cnt=0;
cin>>boss;
ID(boss);
for(int i=1;i<n;i++){
cin>>s>>boss;
sons[ID(boss)].push_back(ID(s));
}
int ans;
ans=max(dp(0,0),dp(0,1));
cout<<ans;
bool unique=false;
if(d[0][0]>d[0][1]&&f[0][0])
unique=true;
if(d[0][0]<d[0][1]&&f[0][1])
unique=true;
if(unique){
cout<<" Yes"<<endl;
}
else{
cout<<" No"<<endl;
}
}
return 0;
}


结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: