简单的树形dp, 先建好图, 然后在dfs的过程中进行dp dp[i][j] 标记j表示人的序号 i有2种状态 1, 0,分别表示此人是否参加聚会。
具体的dp过程 当i为1是, 他的孩子状态必须全部为0, 如果为1是则无硬性要求,只要求人最多。 这题唯一麻烦的便是唯一性的判断,要是如果j取其孩子时,如果孩子不唯一,则j肯定不唯一,这是必然的道理。 具体的判断过程
if(!uni[0][y]) //1的时候只需要看其子节点
uni[1][x] = false;
if(dp[0][y] == dp[1][y]) //0的时候还需要看那种孩子最大,且是否相等。
{
dp[0][x] += dp[0][y];
uni[0][x] = false;
}
else if(dp[0][y] > dp[1][y])
{
if(!uni[0][y])
uni[0][x] = false;
dp[0][x] += dp[0][y];
}
else {
if(!uni[1][y])
uni[0][x] = false;
dp[0][x] += dp[1][y];
}具体代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
const int Maxn = 210;
int MAX(int x,int y) {
return x>y?x:y;
}
vector<int> g[Maxn];
char str[110];
int n, di, dp[2][Maxn];
bool uni[2][Maxn];
void dfs(int x) {
int y;
for(int k = 0; k < g[x].size(); ++k)
{
y = g[x][k];
dfs(y);
}
dp[1][x] = 1, dp[0][x] = 0;
for(int k = 0; k < g[x].size(); ++k)
{
y = g[x][k];
dp[1][x] += dp[0][y];
if(!uni[0][y])
uni[1][x] = false;
if(dp[0][y] == dp[1][y])
{
dp[0][x] += dp[0][y];
uni[0][x] = false;
}
else if(dp[0][y] > dp[1][y])
{
if(!uni[0][y])
uni[0][x] = false;
dp[0][x] += dp[0][y];
}
else {
if(!uni[1][y])
uni[0][x] = false;
dp[0][x] += dp[1][y];
}
}
}
int main(void)
{
while(scanf("%d",&n), n) {
map<string,int> man;
for(int i = 1; i <= n; ++i)
g[i].clear();
scanf("%s",str);
di = 0;
if(man.find(str) == man.end())
man[str] = ++di;
int now, next;
for(int i = 2; i <= n; ++i) {
scanf("%s", str);
if(man.find(str) == man.end())
man[str] = ++di;
now = man[str];
scanf("%s", str);
if(man.find(str) == man.end())
man[str] = ++di;
next = man[str];
g[next].push_back(now);
}
memset(uni, true, sizeof(uni));
memset(dp, 0, sizeof(dp));
dfs(1);
bool flag = false;
if(dp[1][1] == dp[0][1])
flag = true;
else if(dp[1][1] > dp[0][1])
{
if(!uni[1][1])
flag = true;
}
else
{
if(!uni[0][1])
flag = true;
}
cout<<MAX(dp[1][1], dp[0][1]);
if(flag)
cout<<" No"<<endl;
else
cout<<" Yes"<<endl;
}
return 0;
}
本文介绍了一种使用树形动态规划解决聚会参与人数优化问题的方法,通过递归遍历树状结构并进行状态转移,计算不同情况下聚会的最大参与人数。
713

被折叠的 条评论
为什么被折叠?



