我只能说,好难,好巧,好复杂!!!
状态的表示,既有边的,又有点的,好几个数组记录中间答案。
我只能说,好nb。
充分利用了树形的特点,状态设置合理,无敌了呀。
虽然看懂了题解,看了一遍代码,自己写还是很困难。
#include <vector>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 4011
#define E (3*N)
#define INF 0x7fffffff
int next_node[N][N];
int best_drawoff_score[E][E];
int next_node_score[E][3];
int score[E];
int edge_id[N][N];
int dp[E][E];
vector<int> adj[N];
int c[N];
int t, n, id;
void init(){
for (int i = 0; i<=3 * n; ++i){
for (int j = 0; j<=3 * n; ++j){
dp[i][j] = -INF;
best_drawoff_score[i][j] = -INF;
}
}
memset(next_node_score, -1, sizeof(next_node_score));
}
int scoreMax(int ps, int s){
if (s < 0) return 0;
return score[edge_id[ps][s]];
}
int precal(int start, int next, int current, int pre){
next_node[start][current] = next;
int res = 0;
vector<pair<int, int> > candi;
for (vector<int>::iterator it = adj[current].begin();
it != adj[current].end(); ++it){
if (*it == pre) continue;
int tmp = precal(start, next, *it, current);
res = max(res, tmp);
candi.push_back(make_pair(-tmp, *it));
}
sort(candi.begin(), candi.end());
for (int i = 0; i<3 && i<candi.size(); ++i){
next_node_score[edge_id[pre][current]][i] = candi[i].second;
}
return score[edge_id[pre][current]] = res + c[current];
}
int nextNode(int ps, int s, int v1, int v2 = -1){
int e = edge_id[ps][s];
int res = 0;
if (v1 == next_node_score[e][res] || v2 == next_node_score[e][res]) ++res;
if (v1 == next_node_score[e][res] || v2 == next_node_score[e][res]) ++res;
return next_node_score[e][res];
}
int calBestDrawoff(int ps, int s, int pt, int t){
int e1 = edge_id[ps][s];
int e2 = edge_id[pt][t];
if (best_drawoff_score[e1][e2] != -INF){
return best_drawoff_score[e1][e2];
}
if (t == s){
int n1 = nextNode(ps, s, pt);
int n2 = nextNode(pt, t, ps, n1);
return best_drawoff_score[e1][e2] = scoreMax(t,n2);
}
int n1 = nextNode(pt, t, next_node[t][s]);
best_drawoff_score[e1][e2] = scoreMax(t,n1)+c[t];
best_drawoff_score[e1][e2] = max(best_drawoff_score[e1][e2], c[t] + calBestDrawoff(ps, s, t, next_node[t][s]));
return best_drawoff_score[e1][e2];
}
int gao(int ps, int s, int pt, int t){
int e1 = edge_id[ps][s];
int e2 = edge_id[pt][t];
if (dp[e1][e2] != -INF) return dp[e1][e2];
if (s == t){
int n1 = nextNode(ps, s, pt);
int n2 = nextNode(ps, s, pt, n1);
return dp[e1][e2] = scoreMax(s,n1) - scoreMax(s,n2) + c[s];
}
int tmp = next_node[s][t];
dp[e1][e2] = -gao(pt, t, s, tmp) + c[s];
int n1 = nextNode(ps, s, tmp);
dp[e1][e2] = max(dp[e1][e2], c[s] + scoreMax(s,n1) - calBestDrawoff(ps,s,pt,t));
return dp[e1][e2];
}
ofstream out("case.txt");
int main(){
freopen("D-large-practice.in","r",stdin);
freopen("my_D.out","w",stdout);
cin >> t;
for (int cas = 1; cas <= t; ++cas){
cin >> n;
if(cas<=11&&cas>=7) out<<n<<endl;
for (int i = 0; i<n; ++i){
cin >> c[i];
if(cas<=11&&cas>=7) out<<c[i]<<endl;
adj[i].clear();
}
id = 0;
for (int i = 0; i<n; ++i){
edge_id[n][i] = id++;
}
for (int i = 0, j; i<n - 1; ++i){
cin >> j;
if(cas<=11&&cas>=7) out<<j<<endl;
--j;
adj[i].push_back(j);
adj[j].push_back(i);
edge_id[i][j] = id++;
edge_id[j][i] = id++;
}
init();
for (int i = 0; i<n; ++i){
precal(n, i, i, n);
for (vector<int>::iterator it = adj[i].begin();
it != adj[i].end(); ++it){
precal(i, *it, *it, i);
}
}
int ans = -INF;
for (int i = 0; i<n; ++i){
int tmp = INF;
for (int j = 0; j<n; ++j){
int tmp2 = gao(n, i, n, j);
tmp = min(tmp, tmp2);
}
ans = max(ans, tmp);
}
printf("Case #%d: %d\n", cas, ans);
}
}