题意:打游戏。有一个恶魔家族,你的任务是杀光他们,并救出公主,一旦任务完成,游戏结束,问一次游戏最多能玩多久。家族的结构是树状的,如果一个父节点的两个或两个以上的儿子被杀,那么就必须先杀了父节点,否则公主会不测。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; }