はまやんはまやんはまやん

hamayanhamayan's blog

なかよし旅行 [yukicoder No.848]

https://yukicoder.me/problems/no/848

前提知識

解説

https://yukicoder.me/submissions/357498

星2.5にしては、かなり難しい問題に見える。
こういう場合は、制約からエスパーするに限るのだが、N≦2000というのが弱点っぽい。
N^2っぽいので、DPをまず疑ったが、今までかかった時間と、一緒にいた時間を含めることができないので、これではなさそう。
さて、どうするという感じだが、よくあるのが実は最適戦略があるってパターンなので、こっちで攻めてみる。
なんとなく、途中まで一緒に行って、別れて、それぞれ観光名所に行って、合流して戻ってくれば良さそう。
観光名所に行く前に、別れて合流するパターンがあれば、別れた2つの道のうち距離が短い方で一緒に行けば最適化できる。
それっぽい理由もついたし、最初に分かれる所と、最後に合流する所を全探索すると、N^2で計算量もピッタリなので、方針あってそう。
祈って出すとACできる。
 
実装するときには、頂点1, 頂点P, 頂点Qから他への頂点への最短距離が必要になる。
これはダイクストラで各頂点を始点として、計算すればいい。
それぞれ、配列s, 配列p, 配列qとする。
最初に分かれるポイントを頂点a, 最後に合流するポイントを頂点bとする。
すると、全体でかかる時間は、s[a] + max(p[a] + p[b], q[a] + q[b]) + s[b]となる。これがT以下であれば、この行動は実現できる。
このときに一緒にいられない時間はmax(p[a] + p[b], q[a] + q[b])なので、一緒にいられる時間はT - max(p[a] + p[b], q[a] + q[b])となる。
これの最大値が答え。

int N, M, P, Q, T;
//---------------------------------------------------------------------------------------------------
void _main() {
	cin >> N >> M >> P >> Q >> T;
	P--;
	Q--;

	vector<vector<pair<int, int>>> E(N);
	rep(i, 0, M) {
		int a, b, c; cin >> a >> b >> c;
		a--; b--;
		E[a].push_back({ b, c });
		E[b].push_back({ a, c });
	}

	vector<ll> s(N), p(N), q(N);

	dijk(0, E, s);
	dijk(P, E, p);
	dijk(Q, E, q);

	if (s[P] + p[Q] + q[0] <= T) {
		cout << T << endl;
		return;
	}

	ll ans = -1;
	rep(a, 0, N) rep(b, 0, N) {
		ll tot = s[a] + max(p[a] + p[b], q[a] + q[b]) + s[b];
		if (tot <= T) {
			chmax(ans, T - (tot - s[a] - s[b]));
		}
	}
	cout << ans << endl;
}