题意:打游戏。有一个恶魔家族,你的任务是杀光他们,并救出公主,一旦任务完成,游戏结束,问一次游戏最多能玩多久。家族的结构是树状的,如果一个父节点的两个或两个以上的儿子被杀,那么就必须先杀了父节点,否则公主会不测。trick1:这里说的一个家族,最终的结构可能是森林状态。。。
做法:一个家族里有小家族,一棵树里有子树。分成三种状态:杀光一个小家族(kal),杀了一个家族的最长者和部分子孙(skn),不杀长者杀子孙(nkn)。(用贪心的策略领悟即可)。其实真正的挑战在编写阶段,trick巨多。
#include<stdio.h>
#include<string.h>
#define LMT 1005
typedef struct
{
int u,v,next;
}line;
line e[LMT<<1];
int kal[LMT],skn[LMT],nkn[LMT],wei[LMT],next[LMT],snkn[LMT],fa[LMT],dp[LMT];
int n,all;
inline int max(int a,int b)
{
return a>b?a:b;
}
void insert(int u,int v)
{
e[all].u=u;
e[all].v=v;
e[all].next=next[u];
next[u]=all++;
e[all].v=u;
e[all].u=v;
e[all].next=next[v];
next[v]=all++;
}
void inidfs(int u)
{
int v,x,max=-1;
kal[u]=wei[u];
for(x=next[u];x!=-1;x=e[x].next)
if(e[x].v!=fa[u])
{
v=e[x].v;
inidfs(v);
kal[u]+=kal[v];
}
}
void ndfs(int u)
{
nkn[u]=0;
int v,x;
if(snkn[u]==-1)//trick2:一个最优的nkn方案不一定是杀光一个最大子家族,加上另外子家族的nkn
{
snkn[u]=0;
for(x=next[u];x!=-1;x=e[x].next)//居然会在这里多加个分号,一个分号的血案。。。
if(e[x].v!=fa[u])
{
v=e[x].v;
if(nkn[v]==-1)ndfs(v);
snkn[u]+=nkn[v];
}
}
for(x=next[u];x!=-1;x=e[x].next)
if(e[x].v!=fa[u])
{
v=e[x].v;
nkn[u]=max(nkn[u],snkn[u]-nkn[v]+kal[v]);
}
}
void dfs(int u)
{
skn[u]=wei[u];
int v,vv,x,xx;
if(snkn[u]==-1)
{
snkn[u]=0;
for(x=next[u];x!=-1;x=e[x].next)
if(e[x].v!=fa[u])
{
if(nkn[e[x].v]==-1)ndfs(e[x].v);
snkn[u]+=nkn[e[x].v];
}
}
if(dp[u]==-1)//要懂得使用不一定这个副词,很多东西都是不一定的,因此有了DP
{
dp[u]=0;
for(x=next[u];x!=-1;x=e[x].next)
if(e[x].v!=fa[u])
{
for(v=e[x].v,xx=next[u];xx!=-1;xx=e[xx].next)
if(e[xx].v!=v&&e[xx].v!=fa[u])
{
vv=e[xx].v;
if(skn[vv]==-1)dfs(vv);
dp[u]=max(dp[u],snkn[u]-nkn[v]-nkn[vv]+kal[v]+skn[vv]);
}
dp[u]=max(dp[u],snkn[u]-nkn[v]+kal[v]);
}
}
skn[u]+=dp[u];
}
int main()
{
int i,ans;
while(scanf("%d",&n)!=EOF&&n)
{
for(i=0;i<n;i++)
scanf("%d",&wei[i]);
all=0;
memset(next,-1,sizeof(next));
memset(nkn,-1,sizeof(nkn));
memset(skn,-1,sizeof(skn));
memset(kal,0,sizeof(kal));
memset(snkn,-1,sizeof(snkn));
memset(dp,-1,sizeof(dp));
for(i=0;i<n;i++)
{
scanf("%d",&fa[i]);
if(fa[i]!=-1)
insert(fa[i],i);
}
ans=0;
for(i=0;i<n-1;i++)
if(fa[i]==-1)
{
inidfs(i);
ans+=kal[i];
}
inidfs(n-1);
dfs(n-1);
ans+=skn[n-1];
printf("%d\n",ans);
}
return 0;
}