题目大意:给定一个树,选择若干点,使得选择的结点中任一结点不会和它的子结点同时选择,求能选结点最大数量。并且统计方案是否唯一
解题思路:这是一道树状dp的题目,是树的最大独立集合的题,首先使用二维数组d[ i ][ j ]表示选不选 i 结点时能得到的最大人数,j为0表没选,j=1表示选了,因为还涉及到唯一性,所以开一个二维数组bool类型的二维数组f[ i ][ j ]表示选不选 i 结点时方案是不是唯一,j为0表没选,j=1表示选了。
具体的状态方程看代码吧
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
const int maxn=200+10;
int n,d[maxn][2],f[maxn][2];
vector<string> id;
vector<int> son[maxn];
int Find_id(const string &s)
{
for(int i=0;i<id.size();i++)
if(id[i]==s) return i;
id.push_back(s);
return id.size()-1;
}
int dp(int u,int k)
{
d[u][k]=k;
f[u][k]=1;
for(int i=0;i<son[u].size();i++)
{
int v=son[u][i];
if(k==1)
{
d[u][1]+=dp(v,0);
if(!f[v][0]) f[u][1]=0;
}
else
{
d[u][0] += max(dp(v, 0), dp(v, 1));
if(d[v][0] == d[v][1]) f[u][k] = 0;
else if(d[v][0] > d[v][1] && !f[v][0]) f[u][k] = 0;
else if(d[v][1] > d[v][0] && !f[v][1]) f[u][k] = 0;
}
}
return d[u][k];
}
int main()
{
while(scanf("%d",&n)&&n)
{
id.clear();//初始化
for(int i=0;i<n;i++)
son[i].clear();
string s1,s2;
cin>>s1;
Find_id(s1);
for(int i=1;i<n;i++)
{
cin>>s1>>s2;
son[Find_id(s2)].push_back(Find_id(s1));
}
printf("%d ", max(dp(0, 0), dp(0, 1)));
int flag = 0;
if(d[0][0] > d[0][1] && f[0][0]) flag = 1;
if(d[0][1] > d[0][0] && f[0][1]) flag = 1;
if(flag) printf("Yes\n"); else printf("No\n");
}
}