题目大意是某些人将去参加一次party 但是他们和他们不能和他们的上司一起参加,问满足此条件的情况下能去的最多人数
首先由给出的条件建好树,我是用邻接矩阵来存的,主要是为了方便,实际上效率还是比较低的。
需要保存两个状态 一是某节点不用(即此人不去的情况)时该节点和该节点子树的最大值dp[i][0];
二是是用该节点时,该节点及其子树的最大值dp[i][1];
对于dp[i][1] 状态转移方程比较明显 dp[i][1]=1+∑(dp[j][0])j是i的“孩子”;因为 i 去,则他的孩子就不能去了,所以此种情况下,能去的最大人数就是在他所有孩子不去的情况下的最大人数加他自己了。
dp[i][0]:由于i不去,i的孩子j也可去可不去 此时状态转移方程为: dp[i][0]=∑(max(dp[i][0],dp[i][1]))
还需判断去的人数最多的情况,这些人是不是固定的。
对于叶子节点 pan[j][0]=1;pan[j][1]=1;表示人数是确定的。
对于任意节点i dp[i][1] 固定即pan[i][1]=1当且仅当 i 的所有孩子 j pan[j][0]=1;
dp[i][0] :
对于任意一个孩子 j 如果有 dp[ij[0]>dp[j][1]&&pan[j][0]==0或者 dp[j][0]<dp[j][1]&&pan[j][1]==0 或者dp[j][0]==dp[j][1]
pan[i][0]=0;
即,构成dp[i][0]的数据中,如果有一个是不确定的,那么dp[i][0]就是不确定的
我用的是记忆化搜索来实现DP的
代码:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <stdio.h>
#include <map>
#include <algorithm>
using namespace std;
int n;
bool rela[210][210];
bool pan[210][2];
int dp[210][2];
int main()
{
while (cin>>n&&n)
{
memset(rela,0,sizeof(rela));
memset(pan,1,sizeof(pan));
for(int i=0;i<=n;++i){
dp[i][0]=dp[i][1]=-1;
}
map<string,int> myMap;
int i(1);
string a,b;
cin>>a;
myMap[a]=i;
int j(1);
while (j<n)
{
cin>>a;
cin>>b;
if (!myMap.count(a)) myMap[a]=++i;
if (!myMap.count(b)) myMap[b]=++i;
rela[myMap[b]][myMap[a]]=1;
++j;
}
/*
j=1;
while(j<=n){
int k(1);
while(k<=n){
cout<<rela[j][k]<<" ";
++k;
}
cout<<endl;
++j;
}
*/
void dfs(int n);
j=1;
while (j<=n)
{
dfs(j);
++j;
}
bool mul(0);
int maxOut=max(dp[1][1],dp[1][0]);
if(dp[1][1]>dp[1][0]&&!pan[1][1]) mul=1;
if(dp[1][1]<dp[1][0]&&!pan[1][0]) mul=1;
if(dp[1][1]==dp[1][0]) mul=1;
cout<<maxOut<<" ";
if (mul) cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
return 0;
}
void dfs(int num)
{
int j(1);
int tempA(0);
bool mulA(0);
int tempB(0);
bool mulB(0);
bool isLeaf(1);
while (j<=n)
{
if (rela[num][j])
{
isLeaf=0;
if (dp[j][0]==-1)
dfs(j);
if (!pan[j][0]) mulB=1;
tempA+=max(dp[j][1],dp[j][0]);
if ((dp[j][1]>dp[j][0]&&!pan[j][1])||(dp[j][1]<dp[j][0]&&!pan[j][0])||(dp[j][1]==dp[j][0]))
mulA=1;
tempB+=dp[j][0];
}
++j;
}
if (isLeaf)
{
dp[num][0]=0;
dp[num][1]=1;
return;
}
dp[num][0]=tempA;
dp[num][1]=tempB+1;
if (mulA) pan[num][0]=0;
if (mulB) pan[num][1]=0;
return;
}