题目链接:Party at Hali-Bula
题意
转化过来就是树的最大独立集问题,不过多了一个要求判断唯一性。
题解
经典树上dp问题
1.dp定义
d[u][0]和f[u][0]:不选u点能得到最大人数以及方案的唯一性。
( f[u][0]=1表示唯一,0表示不唯一 )
d[u][1]和f[u][1]:选择u点能得到最大人数以及方案的唯一性。
2. 状态转移
(1) d(u,1)=sum{d(v,0)} (v是u的儿子节点集合) 。
如果有一个f(v,0)是0,那么f(u,0)为0.
(2) d(u,1)=sum{max(d(v,0),d(v,1))}。
如果d(v,1)==d(v,0)相等,f(u,1)为0;还有在d(u,1)选择大的d(v,i)里,如果f(v,i)为0,则 f(u,1)为0。
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
using namespace std;
//extern "C" {void *__dso_handle=0; }
typedef long long ll;
const int maxn=205;
map<string,int> book;
vector<int> g[maxn];
int d[maxn][2],f[maxn][2];
void dfs(int u)
{
if(f[u][1]!=-1) return ;
f[u][1]=1;
f[u][0]=1;
d[u][1]=1;
d[u][0]=0;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
dfs(v);
d[u][1]+=d[v][0];
if(f[v][0]==0) f[u][1]=0;
if(d[v][0]>=d[v][1])
{
d[u][0]+=d[v][0];
if(f[v][0]==0) f[u][0]=0;
}
else
{
d[u][0]+=d[v][1];
if(f[v][1]==0) f[u][0]=0;
}
if(d[v][0]==d[v][1]) f[u][0]=0;
}
}
int main()
{
int n;
while(cin >> n && n)
{
memset(d,-1,sizeof(d));
memset(f,-1,sizeof(f));
book.clear();
for(int i=1;i<=n;i++) g[i].clear();
string boss; cin >> boss;
int cnt=1;
book[boss]=cnt++;
for(int i=1;i<n;i++)
{
string em,bo; cin >> em >> bo;
if(!book[em]) book[em]=cnt++;
if(!book[bo]) book[bo]=cnt++;
g[book[bo]].push_back(book[em]);
}
dfs(book[boss]);
if(d[book[boss]][0]>=d[book[boss]][1])
{
cout << d[book[boss]][0] << ' ';
if(d[book[boss]][0]==d[book[boss]][1]) cout << "No" << endl;
else if(f[book[boss]][0]) cout << "Yes" << endl;
else cout << "No" << endl;
}
else
{
cout << d[book[boss]][1] << ' ';
if(f[book[boss]][1]) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
}