题目链接:
http://poj.org/problem?id=3342
题解:
开一个dp数组,dp[i][0]表示第i个人不去能得到的最大价值,dp[i][1]表示第i个人去能得到的最大价值。
状态转移方程为:
dp[i][1] += dp[i-1][0];
dp[i][0] += max(dp[i-1][0],dp[i-1][1]); (注意,在这里产生是否为唯一解)
dp数组解决完毕后,接下来只要进行一次dfs就可以了。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int dp[6050][2],bos[6040];
int N,boss,cnt;
string name[210];
int findSon(int node)
{
int ans = 0;
for(int i = 1; i <=N; i++)
{
if(bos[i] == node)
ans++;
}
return ans;
}
void dfs(int node)
{
for(int i = 1; i <= N; i ++)
{
if(bos[i] == node)
{
dfs(i);
dp[node][1] += dp[i][0];
dp[node][0] += max(dp[i][0], dp[i][1]);
}
}
}
int check(int node)
{
if(!findSon(node))return 1;//底下没有节点了,也就不存在多个解的情况了
if(dp[node][0] == dp[node][1])return 0;//相等时出现多个解的情况
if(dp[node][0] < dp[node][1])//使用父节点
{
for(int i = 1; i <= N; i++)
{
if(bos[i] == node)//这个节点不可以用,接着搜这个节点的子节点
{
for(int j = 1; j<= N; j++)
{
if(bos[j] == i && !check(j))
return 0;
}
}
}
}
else if(dp[node][0] > dp[node][1])//不使用父节点
{
for(int i = 1; i <= N; i++)
{
if(bos[i] == node && !check(i))
return 0;
}
}
return 1;
}
int match(string s)
{
for(int i = 1; i < cnt; i++)
{
if(name[i] == s)
return i;
}
name[cnt] = s;
return cnt++;
}
int main()
{
while(cin >> N)
{
if(N == 0)break;
for(int i = 1; i <= N; i++)
{
dp[i][1] = 1;
}
cin >> name[1];
string a,b;
int f = 0; cnt = 2;
for(int i = 2; i <= N; i++)
{
cin >> a >> b;
bos[match(a)] = match(b);
}
boss = 1;
dfs(boss);
int flag = check(boss);
cout << max(dp[boss][0],dp[boss][1]) << " ";
if(flag == 1)
cout << "Yes" <<endl;
else
cout << "No" <<endl;
memset(bos, 0 , sizeof(bos));
memset(dp,0,sizeof(dp));
}
return 0;
}