例题9-13 Hali-Bula的晚会 UVa1220

1.题目描述:点击打开链接

2.解题思路:本题几乎就是树的最大独立集问题,只不过多了一个判断解的唯一性的要求。针对这种情况,可以做如下定义:

(1)d(u,0),f(u,0)分别表示以u为根的子树中,不选u点的最大人数和方案的唯一性(f=1表示唯一,f=0表示不唯一);

(2)d(u,1),f(u,1)分别表示以u为根的子树中,选u点的最大人数和方案的唯一性(f=1表示唯一,f=0表示不唯一);

相应的,状态转移方程也要有两种情况:

(1)d(u,1)的计算:由于选择了u,那么u的子结点都不能选。因此,d(u,1)=sum{d(v,0)|v是u的子结点}。当且仅当所有的f(v,0)=1时,f(u,1)才是1.

(2)d(u,0)的计算:因为u没有选,因此它的子结点可选可不选。因此,d(u,0)=sum{max(d(v,0),d(v,1))}。公式中先找到每个子结点的最大值,再求和。唯一性的判断:(i)如果d(v,0)==d(v,1),那么方案不唯一;(ii)如果max取到的那个结点的f=0,方案也不唯一。

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

#define maxn 200+10
int d[maxn][2];
int f[maxn][2];
map<string, int>IDcache;
vector<string>name;
vector<int>boss[maxn];
int n;
int ID(string s)
{
	if (IDcache.count(s))
		return IDcache[s];
	name.push_back(s);
	return IDcache[s] = name.size() - 1;
}
int is_unique(int d1, int d2, int f1, int f2)//判断方案是否唯一
{
	if (d1 == d2)return 0;
	else return (d1 > d2) ? f1 : f2;
}
int dp(int id, int flag)//根据flag分类讨论
{
	int&ans = d[id][flag];
	if (ans >= 0)return ans;
	ans = 0;
	if (flag)
	{
		if (boss[id].empty()){ f[id][flag] = 1; return ans = 1; }
		int k = boss[id].size();
		int ok = 1;
		for (int i = 0; i < k; i++)
		{
			ans += dp(boss[id][i], 0);
			if (f[boss[id][i]][0] != 1)
				ok = 0;
		}
		ans++;
		if (ok)f[id][flag] = 1;
		else f[id][flag] = 0;
	}
	else
	{
		if (boss[id].empty()){ f[id][flag] = 1; return ans = 0; }
		int k = boss[id].size();
		int ok = 1;
		for (int i = 0; i < k; i++)
		{
			int d1 = dp(boss[id][i], 0);
			int d2 = dp(boss[id][i], 1);
			int tmp = max(d1, d2);
			ans += tmp;
			if (!is_unique(d1, d2, f[boss[id][i]][0], f[boss[id][i]][1]))
				ok= 0;
		}
		if (ok)f[id][flag] = 1;
		else f[id][flag] = 0;
	}
	return ans;
}
int main()
{
	//freopen("test.txt", "r", stdin);
	while (scanf("%d", &n)&& n)
	{
		name.clear();
		IDcache.clear();//注意每次重新使用时清空name,IDcache
		memset(d, -1, sizeof(d));
		memset(f, 0, sizeof(f));
		memset(boss, 0, sizeof(boss));
		string s, t;
		cin >> s;
		int id = ID(s);
		for (int i = 1; i < n; i++)
		{
			cin >> s >> t;
			int d1 = ID(s), d2 = ID(t);
			boss[d2].push_back(d1);
		}
		int ans, ff;
		int d1 = dp(id, 0);
		int d2 = dp(id, 1);
		ans = max(d1, d2);
		if (!is_unique(d1, d2, f[id][0], f[id][1]))
			ff = 0;
		else ff = 1;
		printf("%d %s\n", ans, ff ? "Yes" : "No");
	}
	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值