题目意思太罗嗦,不解释了。这道题一开始一直Segmentation Fault,问了秦总才发现可能是数组放在dfs里面的关心后来又wa了无数次,结果是因为它居然可以是个森林!!!简直报警了,题目中明明说的是Koopa的所有儿子,居然还可以存在森林。唉。。。
这道题好事蛮不错的一道题,每一个点有三种状态:dp[i][0],dp[i][1],dp[i][2]。dp[i][1]代表第i个人刚刚被干掉,第i个节点及其子树的最大值。dp[i][0]代表第i个节点即所有节点的t[i]值之和。dp[i][2]代表的是第i个节点没有被干掉所能干掉其子树的最大值和。
下面来写转移方程:
dp[u][0] = t[u] + sum{dp[v][0]};
dp[u][2] = max{dp[v][0] + sum{dp[w][2] | w != v} = max{dp[v][0]-dp[v][2])}+ sum{dp[v][2]}; 这两个v相互独立
dp[u][1] = max{dp[v][0]-dp[v][2] + dp[w][1] - dp[w][2] | w != v} + sum{dp[v][2]};
注意下一边界条件就可以开始写了。。。算 dp[v][0]-dp[v][2]+dp[w][1]-dp[w][2]的最大值的时候有一个小技巧,直接看我的代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define FOR(i,x,y) for(int i = x;i < y;i ++)
using namespace std;
const int MAXN = 2222;
int n,dp[MAXN][3],t[MAXN],head[MAXN],edge_cnt; //dp[i][0]表示i个节点和他的所有子树都被杀了,dp[i][1]表示第一次i个节点被杀了,dp[i][2]表示i个节点没被杀
int st[MAXN];
struct Edge{
int to,next;
}edge[MAXN<<1];
bool cmp(int x,int y) {return x>y;}
void add_edge(int u,int v){
edge[edge_cnt].to = v;
edge[edge_cnt].next = head[u];
head[u] = edge_cnt++;
}
void dfs(int u,int fa){
dp[u][0] = dp[u][1] = t[u]; dp[u][2] = 0;
int cnt = 0;
int dp2 = -1;
int sum = 0;
int dp00 = -1,dp01 = -1,dp10 = -1,dp11 = -1; ///dp00 代表dp[v][0]-dp[v][2]的最大值,dp01代表第二大值,dp10同理
for(int i = head[u];i != -1;i = edge[i].next){
int v = edge[i].to;
if(v == fa) continue;
dfs(v,u);
dp[u][0] += dp[v][0];
sum += dp[v][2];
if((dp[v][0]-dp[v][2]) >= dp00){
dp01 = dp00;
dp00 = dp[v][0]-dp[v][2];
}
else dp01 = max(dp01,t[v]);
if(dp[v][1]-dp[v][2] >= dp10){
dp11 = dp10;
dp10 = dp[v][1]-dp[v][2];
}
else dp11 = max(dp11,dp[v][1]-dp[v][2]);
dp2 = max(dp2,dp[v][0]-dp[v][2]+dp[v][1]-dp[v][2]);
cnt++;
}
if(!cnt) return;
if(cnt == 1){
dp[u][1] += sum+dp00;
dp[u][2] += sum+dp00;
}
else{
if(dp00 + dp10 == dp2) {
if(dp01 == dp00 || dp11 == dp10)
dp[u][1] += sum+dp2;
else
dp[u][1] += sum+max(dp00+dp11,dp01+dp10);
}
else
dp[u][1] += sum + dp00 + dp10;
dp[u][2] += sum+dp00;
}
return;
}
int dfs2(int u,int fa){
int ans = t[u];
for(int i = head[u];i != -1;i = edge[i].next){
int v = edge[i].to;
if(v == fa) continue;
ans += dfs2(v,u);
}
return ans;
}
int main()
{
freopen("test.in","r",stdin);
while(~scanf("%d",&n) && n){
memset(head,-1,sizeof(head));
edge_cnt =0;
FOR(i,0,n) scanf("%d",&t[i]);
int to;
int st_cnt = 0;
FOR(i,0,n){
scanf("%d",&to);
if(to == -1){
st[st_cnt++] = i;
continue;
}
add_edge(i,to);
add_edge(to,i);
}
int ans = 0;
FOR(i,0,st_cnt-1) ans += dfs2(st[i],-1);
dfs(n-1,-1);
printf("%d\n",ans+dp[n-1][1]);
}
return 0;
}