您的位置:首页 > 其它

树形DP解 POJ3342-Party at Hali-Bula

2016-02-11 12:21 295 查看
参考:/article/8683104.html

第一次接触树形DP的题目,这种题解题思路还挺固定的,深度优先搜索+动态规划。这点比较好理解,dp[i][j]保存节点i在状态j下的最多参加宴会人数,状态j其实就两种状态,也就是只有2种取值,0代表不参加,1代表参加。

首先赋初值,dp[i][0]=0,就结点i一人来说,不参加,人数为0;dp[i][1]=1,参加,就有一个人了。

当f参加时,dp[f][0] = dp[f][0] + Sigma max( dp[p][0] , dp[p][1] ) ,这里p是f的儿子结点。对于每个儿子结点,做父亲的都要考虑,各儿子拿出自己最好的状态(0和1两种情况。不一定他们参加,值就最大,可以不参加),由父亲汇总,(父亲自己是不参加的,初始状态值dp[f][0]为0)。这个Sigma代表求和,博客里不会打公式符号。

当f参加时,dp[f][1] =dp[f][1] + Sigma dp[p][0],这里父亲自己参加,dp[f][1]初值是1,此时儿子都不能参加,

这题难点可能就是判断结果方案是否唯一上面。看上面博客的这段代码开始怎么也不能理解,后来翻看别人的博客,总算是有些眉目。很多人这里求解都是另外设个和dp数组一样的二维布尔状态数组保存当前方案是否唯一,随着dp求解的同时一直状态转移到根结点得出结果,上面参考代码是在dp求解结束时,利用dp结果的特性来得出结论的。前者节省时间,后者节省空间,不过我更喜欢后者的简洁。它的大意:如果算到儿子结点时,方案有不唯一的,后面的不用算了,整个方案肯定都不唯一。看上面当f不参加时的状态方程:dp[f][0]
= dp[f][0] + Sigma max( dp[p][0] , dp[p][1] ), 如果某个儿子结点p参不参加都一样,也就是dp[p][0]=dp[p][1],那可以判定,整个方案解是不唯一的。但是,这个前提是在计算父结点f时,你选用了这个不参加时的状态方程,而不是另一个f参加时的方程:dp[f][1]
= dp[f][1] + Sigma dp[p][0]。那如何才能选这个方程呢,当然是f不参加时,总参加人数更多呗,也就是dp[f][0]>dp[f][1]。注意一点,这里判断都是基于儿子p判断f的,最后一步时,没考虑f结点自身,所以要稍微处理一下。讲到这,代码就很好理解了。

<span style="font-size:12px;">#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
vector<int> vec[205];
map<string,int> mp;
char str[205][105];
char tmp[105];
char a[105],b[105];
int dp[205][2];
int k;

void dfs(int root)
{
for(int i=0; i<vec[root].size(); i++)
{
int v=vec[root][i];
dfs(v);
dp[root][0]+=max(dp[v][0],dp[v][1]);
dp[root][1]+=dp[v][0];
}
}
int main()
{
//freopen("in.txt","r", stdin);
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==0)
break;
k=0;
mp.clear();
scanf("%s",tmp);
mp[tmp]=k++;
for(int i=0; i<n; i++)
{
vec[i].clear();
dp[i][0]=0;		//初始时,结点i不被选中时的结点数为0,选中时为1
dp[i][1]=1;
}
for(int i=1; i<n; i++)
{
scanf("%s%s",a,b);
if(mp.find(a)==mp.end()) mp[a]=k++;
if(mp.find(b)==mp.end()) mp[b]=k++;
vec[mp[b]].push_back(mp[a]);
}
dfs(0);
//下面代码判断是不是唯一的方案
int flag=1;
for(int i=0; i<n; i++)
{
if(dp[i][0]>dp[i][1])
{
for(int j=0; j<vec[i].size(); j++)
{
int v=vec[i][j];
if(dp[v][0]==dp[v][1])
{
flag=0;
break;
}
}
}
if(flag==0)
break;
}
if(flag==0 || dp[0][0]==dp[0][1])//注意判断条件,
printf("%d No\n",max(dp[0][0],dp[0][1]));
else
printf("%d Yes\n",max(dp[0][0],dp[0][1]));
}
return 0;
}
/*
6
Jason
Jack Jason
Joe Jack
Jill Jason
John Jack
Jim Jill
2
Ming
Cho Ming
0
*/</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: