这道题需要很仔细才能AC啊,本菜搞了好久才A~
题意:
你要营救的人被关在最后一个城堡 (n-1)
先给你n个数,表示征服每个城堡所需要的时间
再给你n个数,表示每个城堡(从0开始)的父亲节点是谁,题目保证 城堡 n-1 没有父节点
另外有一些规则,如果一个城堡有两个或以上的儿子被征服了,那么这个城堡的主人就会生气,他就会将这件事告诉他的父亲节点,然后层层往上一直到最后一个城堡(n-1),那么你要救的人就会被杀掉,所以你在杀掉某个节点 u 的两个儿子的时候就必须跑到u城堡去杀u,当你征服最后一个城堡(n-1)的时候游戏就结束了
问:这个游戏最多能玩多少时间。
已经有人写了一个很详细的解题报告,所以我就懒的写了
注意一点:如果给你一个森林,怎么办
http://hi.baidu.com/sheep_finalfreedom/blog/item/7879bb2b995c04f598250a7a.html
首先我们考虑king koopa,当他被打败的时候,游戏必须结束,所以他最多有两个儿子被打败,而且对于第二个被打败的儿子,也是同样的情况,即king koopa的【第二个被打败的儿子】最多有两个儿子被打败,而king koopa的第一个被打败的儿子,以它(这个它指的是king koopa的第一个被打败的儿子)为根的整棵子树都能被打掉,比如它有三个儿子,那么其中2只被打败之后,我们必须马上去打他们的father,但是father打完之后我们还可以倒回去把剩下的那个儿子给收拾掉!
上面已经考虑到了DP的两个方面,我们用sum【i】来表示【完全打败】以i为根的子树所用的时间,dp【i】
表示以i为根的时候,i最多只能有两个儿子被打败时所用的时间(因为它的其他儿子已经来不及打了,king koopa的倒下会直接结束游戏!)
但是还有一个地方需要考虑进去,假设king koopa有4个儿子,我们只能打掉其中2只,另外2只不能动,但是并不代表这两只的儿子也不能打,相反,作为贪心的超级玛丽,我们必须去打这两只的后代!
所以用more【i】来表示以i为根的子树,i不被打败时的最大游戏时间
more【i】=max(sum【child1】+more【otherchildren】)枚举这个child1
则dp【i】=max(sum【child1】+dp【child2】+more【otherchildren】)枚举child1和child2
下面是我的代码
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define CLR(v) memset(v,0,sizeof(v));
const int maxn = 1010;
int val[maxn];
vector<int> edge[maxn];
int more[maxn],dp[maxn],sum[maxn];
void get_sum(int u,int f)
{
sum[u]=val[u];
int sz=edge[u].size();
for(int i=0;i<sz;i++)
{
int v=edge[u][i];
if(v==f) continue;
get_sum(v,u);
sum[u]+=sum[v];
}
}
void get_more(int u,int f)
{
more[u]=0;
int sz=edge[u].size();
int s=0;
for(int i=0;i<sz;i++)
{
int v=edge[u][i];
if(v==f) continue;
get_more(v,u);
}
for(int i=0;i<sz;i++) s+=more[edge[u][i]];
for(int i=0;i<sz;i++)
{
int v=edge[u][i];
more[u]=max(more[u],sum[v]+s-more[v]);
}
}
bool vis[maxn];
void dfs(int u,int f)
{
dp[u]=val[u];
int sz=edge[u].size();
if(sz==1) dp[u]=max(dp[u],sum[edge[u][0]]+val[u]);
int s=0;
for(int i=0;i<sz;i++)
{
int v=edge[u][i];
if(v==f) continue;
dfs(v,u);
}
for(int i=0;i<sz;i++) s+=more[edge[u][i]];
for(int i=0;i<sz;i++)
{
for(int j=i+1;j<sz;j++)
{
int son1=edge[u][i];
int son2=edge[u][j];
dp[u]=max(dp[u],dp[son1]+sum[son2]+s-more[son1]-more[son2]+val[u]);
dp[u]=max(dp[u],dp[son2]+sum[son1]+s-more[son1]-more[son2]+val[u]);
}
}
}
bool root[maxn];
int main()
{
int n;
while(scanf("%d",&n),n)
{
for(int i=0;i<n;i++) scanf("%d",&val[i]),edge[i].clear();
memset(root,false,sizeof(root));
for(int i=0,j;i<n;i++)
{
scanf("%d",&j);
if(j==-1) root[i]=true;
if(j!=-1) edge[j].push_back(i);
}
CLR(dp);CLR(more);CLR(sum);
int ans=0;
for(int i=0;i<n-1;i++)
{
if(root[i])
{
get_sum(i,-1);
ans+=sum[i];
}
}
get_sum(n-1,-1);
get_more(n-1,-1);
dfs(n-1,-1);
printf("%d\n",ans+dp[n-1]);
}
return 0;
}