google code jam 2014 RC_D

我只能说,好难,好巧,好复杂!!!

状态的表示,既有边的,又有点的,好几个数组记录中间答案。

我只能说,好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);
	}
}
















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值