首先题目说得明明白白“形成一个树状结构”,树状DP是没逃了……
在这里我给出的是紫书思路的一种实现,具体请看紫书P282。
d ( u , 0 ) d(u,0) d(u,0) 表示以 u u u 为根的子树中,不选 u u u 点能邀请的最大人数。 f ( u , 0 ) f(u,0) f(u,0) 表示方案是否唯一(1表示唯一,0表示不唯一)。
d ( u , 1 ) d(u,1) d(u,1) 表示以 u u u 为根的子树中,选 u u u 点能邀请的最大人数。 f ( u , 1 ) f(u,1) f(u,1) 表示方案是否唯一。
状态转移方程挺好写的,设 S S S 表示节点 u u u 的集结点集合。
由于选了 u u u, u u u 的所有子节点都不能选:
d ( u , 1 ) = ∑ i ∈ S d d(u,1)=\sum_{i\in S}d d(u,1)=∑i∈Sd( i i i),当且仅当所有 f ( 1 , 0 ) f(1,0) f(1,0) 都是 1 1 1 时 f ( u , 1 ) f(u,1) f(u,1) 才是 1 1 1。
没选 u u u 就随便了,子节点可选可不选QAQ:
d ( u , 0 ) = ∑ i ∈ S m a x ( d ( i , 0 ) , d ( i , 1 ) ) d(u,0)=\sum_{i\in S}max(d(i,0),d(i,1)) d(u,0)=∑i∈Smax(d(i,0),d(i,1)),当且仅当 m a x max max 取到的对应的那个 f f f 为 1 1 1 并且所有 d ( i , 0 ) ≠ d ( i , 1 ) d(i,0) \neq d(i,1) d(i,0)=d(i,1) 时 f ( u , 0 ) f(u,0) f(u,0) 才为1。
这里解释一下代码中的 unordered_map
, 这是C++11里的容器,是一个没有排序的 map
光看名字就知道,比普通的 map
少一个 log的时间复杂度,底层实现是hash表,虽然此题。map
也能过
另外注意字符串的输入,这里不得不用cin
牺牲一点读入时间。。。
多测不清空,爆零两行泪!
C o d e : ( C + + 11 ) Code:(C++11) Code:(C++11)
#include <cstdio>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <cstring>
#define _for(i, a, b) for (int i = (a); i < (b); i ++)
#define _rep(i, a, b) for (int i = (a); i <= (b); i ++)
using namespace std;
int cnt;
unordered_map<string, int> m;
inline int Hash (string x)//将字符串映射到整数上
{
if (m[x] == 0) m[x] = ++ cnt;
return m[x];
}
vector <int> sons[205];
int d[205][2], f[205][2];
inline void dfs(int u)
{
d[u][1] = 1;
int t = sons[u].size();
_for (i, 0, t)
{
auto son = sons[u][i];
dfs(son); //根本不用记忆化化,因为本来就是树形结构,根本不会重复
d[u][1] += d[son][0];
if (d[son][0]) f[u][1] &= f[son][0];//只要一个f[son][0]为0f[u][1]即为0
if (d[son][0] < d[son][1])
f[u][0] &= f[son][1], d[u][0] += d[son][1];//同理
else if (d[son][0] > d[son][1])
f[u][0] &= f[son][0], d[u][0] += d[son][0];
else d[u][0] += d[son][0], f[u][0] = 0;//两个都一样肯定多解了
}
}
int main()
{
int n, boss;//boss乃大老板也QAQ
string ch, ch2;
while (1)
{
cnt = 0;
m.clear();
memset(d, 0, sizeof(d));
memset(f, 1, sizeof(f));
scanf("%d", &n);
if (n == 0) return 0;
_rep (i, 1, n) sons[i].clear();
cin >> ch;
boss = Hash(ch);
d[boss][0] = d[boss][1] = 0;
_for (i, 1, n)
{
cin >> ch >> ch2;
sons[Hash(ch2)].push_back(Hash(ch));
}
dfs(boss);
if (d[boss][1] >= d[boss][0])
{
printf("%d ", d[boss][1]);
if (f[boss][1] && d[boss][1] != d[boss][0]) puts("Yes");//论输出格式的重要性
else puts("No");
}
else
{
printf("%d ", d[boss][0]);
if (f[boss][0]) puts("Yes");
else puts("No");
}
}
}