例题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;
}



时间: 2024-08-05 06:50:18

例题9-13 Hali-Bula的晚会 UVa1220的相关文章

武汉科技大学ACM :1007: 华科版C语言程序设计教程(第二版)例题4.13

Problem Description 输入两个整数,求他们的最大公约数和最小公倍数. Input 两个整数. Output 最大公约数和最小公倍数. Sample Input 12 9 Sample Output 3 36 HINT 可以把求最小公约数和最小公倍数写成函数,方便以后调用. 1 #include <stdio.h> 2 3 void main() 4 5 { 6 7 int m,n; 8 9 while(scanf("%d%d",&m,&n)

例题3.13 周期 LA3026

1.题目描述:点击打开链接 2.解题思路:本题利用KMP算法中失配函数的性质解决.我们仔细观察失配函数f就会发现,如果一个字符串P是一个周期串,且它的最后一个位置是i,那么i-f[i]一定是该周期串的一个最小的循环节的长度,这样,最大的k值就是i/(i-f[i]).这样,我们只需要寻找f[i]>0(因为k>0,因此不能让i-f[i]==i)且i%(i-f[i])==0的位置即可. 3.代码: #include<iostream> #include<algorithm>

python 各模块

01 关于本书 02 代码约定 03 关于例子 04 如何联系我们 1 核心模块 11 介绍 111 内建函数和异常 112 操作系统接口模块 113 类型支持模块 114 正则表达式 115 语言支持模块 12 _ _builtin_ _ 模块 121 使用元组或字典中的参数调用函数 1211 Example 1-1 使用 apply 函数 1212 Example 1-2 使用 apply 函数传递关键字参数 1213 Example 1-3 使用 apply 函数调用基类的构造函数 122

转:Python标准库(非常经典的各种模块介绍)

Python Standard Library 翻译: Python 江湖群 10/06/07 20:10:08 编译 0.1. 关于本书 0.2. 代码约定 0.3. 关于例子 0.4. 如何联系我们 核心模块 1.1. 介绍 1.2. _ _builtin_ _ 模块 1.3. exceptions 模块 1.4. os 模块 1.5. os.path 模块 1.6. stat 模块 1.7. string 模块 1.8. re 模块 1.9. math 模块 1.10. cmath 模块

2016vijos 1-3 兔子的晚会(生成函数+倍增FWT)

求出序列的生成函数后,倍增FWT #include<cstdio> using namespace std; #define N 2048 const int mod=1e9+7; int inv; int f[N+1]; int Pow(int a,int b) { int res=1; for(;b;a=1LL*a*a%mod,b>>=1) if(b&1) res=1LL*res*a%mod; return res; } void FWT(int *a,int n) {

acm常见算法及例题

转自:http://blog.csdn.net/hengjie2009/article/details/7540135 acm常见算法及例题 初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法

黑书例题 Fight Club 区间DP

题目可以在bnuoj.soj等OJ上找到. 题意: 不超过40个人站成一圈,只能和两边的人对战.给出任意两人对战的输赢,对于每一个人,输出是否可能是最后的胜者. 分析: 首先序列扩展成2倍,破环成链. dp[i][j]表示i和j能够相遇对打,那么dp[i][i+n]为真代表可以成为最后胜者. 枚举中间的k,若i和j都能和k相遇,且i和j至少一人能打赢k,那么i和j可以相遇. 复杂度o(n^3) 1 #include<cstdio> 2 #include<cstring> 3 usi

【强连通分量】tarjan算法及kosaraju算法+例题

阅读前请确保自己知道强连通分量是什么,本文不做赘述. Tarjan算法 一.算法简介 Tarjan算法是一种由Robert Tarjan提出的求有向图强连通分量的时间复杂度为O(n)的算法. 首先我们要知道两个概念:时间戳(DFN),节点能追溯到的最早的栈中节点的时间戳(LOW).顾名思义,DFN就是在搜索中某一节点被遍历到的次序号(dfs_num),LOW就是某一节点在栈中能追溯到的最早的父亲节点的搜索次序号. Tarjan算法是基于深度优先搜索的算法.在搜索过程中把没有Tarjan过的点入栈

第10章例题(紫书)

21/21 题目都很基础,有很多题书上讲得比较详细,然后隔得时间有点久,所以具体什么trick都忘了,思路也懒得去回忆,所以将就着放上来了.... 例题10–1 Uva 11582 题意:输入a, b, n让你计算F[a^b]%n;其中这个F[i]是斐波那契数: 题解: 这题是快速幂+找循环节,用什么方法找循环节呢?因为第一个数是0和1,然后当再出现0和1的时候就是出现循环节的时候,然后假如找到了循环节T,然后就有F[n] = F[n % T],预处理找循环节,O(一百万左右),快速幂logn