题解UVa1220 Hali-Bula的晚会

刘汝佳大法好!

是不是感觉看到这题很熟悉?好像很像没有上司的舞会这题诶!

可是我们发现,这里还新加了一个“判断唯一性”的任务。

我们定义:

d(u,0)d(u,0)表示不选uuuu的子树的最大独立集的节点个数

d(u,1)d(u,1)表示选uuuu的子树的最大独立集的节点个数

f(u,0)f(u,0)表示不选uuuu的子树的最大独立集的唯一性(00不唯一,11唯一)

f(u,1)f(u,1)表示选uuuu的子树的最大独立集的唯一性(00不唯一,11唯一)

d(u,1)=1+(u,v)Ed(v,0)d(u,1)=1+\sum_{(u,v)\in E}d(v,0)

d(u,0)=(u,v)Emax{d(v,0),d(v,1)}d(u,0)=\sum_{(u,v)\in E}\max\{d(v,0),d(v,1)\}

以上两个就是求最大独立集的转移方程。

然后考虑怎么判断唯一性。

对于f(u,1)f(u,1)的情况:如果uu的任意一个儿子vvf(v,0)=0f(v,0)=0,那么f(u,1)f(u,1)就等于00

对于f(u,0)f(u,0)的情况:设vvuu的任意一个儿子

  • d(v,0)=d(v,1)d(v,0)=d(v,1),则f(u,0)=0f(u,0)=0
  • d(v,0)>d(v,1)d(v,0)>d(v,1)f(v,0)=0f(v,0)=0,则f(u,0)=0f(u,0)=0
  • 反之亦然。

以下为代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int N=205;
int n,tot=0,target[N],pre[N],last[N];
int d[N][2],f[N][2];
map<string,int> mp;
void add(int u,int v) {
target[++tot]=v;
pre[tot]=last[u];
last[u]=tot;
}
void dfs(int u) {
if(!last[u]) {
d[u][0]=0;f[u][0]=1;
d[u][1]=f[u][1]=1;
return ;
}
f[u][1]=1;f[u][0]=1;
d[u][0]=0;d[u][1]=1;
for(int ptr=last[u];ptr;ptr=pre[ptr]) {
dfs(target[ptr]);
if(f[target[ptr]][0]==0) f[u][1]=0;
d[u][1]+=d[target[ptr]][0];

int v=target[ptr];
if(d[v][0]==d[v][1]) f[u][0]=0,d[u][0]+=d[v][0];
else if(d[v][0]>d[v][1]) {
if(!f[v][0])f[u][0]=0;
d[u][0]+=d[v][0];
}
else if(d[v][0]<d[v][1]) {
if(!f[v][1])f[u][0]=0;
d[u][0]+=d[v][1];
}
}
}
int main(){
while(cin>>n && n) {
string x,y;
mp.clear();
tot=0;
memset(last,0,sizeof(last));
cin>>x;
int cnt=0;
mp[x]=++cnt;
rep(i,1,n-1) {
cin>>x>>y;
if(!mp.count(x)) mp[x]=++cnt;
if(!mp.count(y)) mp[y]=++cnt;
add(mp[y],mp[x]);
}
dfs(1);
if(d[1][0]==d[1][1]) printf("%d No\n",d[1][0]);
else if(d[1][0]>d[1][1]) {
printf("%d ",d[1][0]);
if(!f[1][0]) printf("No\n");
else printf("Yes\n");
}
else if(d[1][0]<d[1][1]) {
printf("%d ",d[1][1]);
if(!f[1][1]) printf("No\n");
else printf("Yes\n");
}
}
return 0;
}