AtCoder

ABC035 D問題(トレジャーハント)を解く

AtCoder_ABC035_D

AtCoder が提供しているABC(AtCoder Beginner Contest)035 D問題をC++で解いてみました。ABC035は、2016年3月26日21:00に実施されました。

AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。

D問題 トレジャーハント(Difficulty : 1591(参考値))

問題の詳細は、リンク先をご覧ください。

ABC035 D問題 トレジャーハント

ダイクストラ法を少し工夫して使います。AtCoder Problems による Difficulty は 1591(参考値)でした。

解答案

所持金を最大化するためには、1か所の町に滞在するのが最適です。複数の町に滞在しても、所持金の最大値が増えることはないためです。

始点である頂点1から他の全ての頂点への最短距離(問題設定では時間)は、ダイクストラ法を用いて求められます。帰路として、全ての頂点から頂点1への最短距離を求める必要があります。これは、グラフの辺の向きを逆にした上で、頂点1から全ての頂点への最短距離を求めることで実現できます。

C++ プログラム例(ABC035D)

グラフ $G$ とその辺の向きを逆にしたグラフ $rG$ を設定します(24ー30行目)。ダイクストラ法の定番コードを使って、グラフ $G$ グラフ $rG$ の頂点1からすべての頂点への最短距離を求めます。

最後に滞在する町を決めて、所持金の最大値を求めます。以下が、C++プログラムです。

#include <bits/stdc++.h>
using namespace std;

typedef long long int ll;
#define INF (1LL << 60)
typedef pair<ll, int> P;
struct Edge {
	int to;
	ll weight;
	Edge() {}
	Edge(int t, ll w) : to(t), weight(w) {}
};

int main()
{
	int n, m;
	ll t;
	cin >> n >> m >> t;
	vector<ll> a(n + 1);
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
	}
	vector<vector<Edge>> G(n + 1), rG(n + 1);
	for (int i = 0; i < m; ++i) {
		int u, v;
		ll c;
		cin >> u >> v >> c;
		G[u].push_back(Edge(v, c));
		rG[v].push_back(Edge(u, c));
	}

	vector<ll> dist(n + 1, INF);
	priority_queue<P, vector<P>, greater<P>> que;
	dist[1] = 0;
	que.push(P(0, 1));
	while (!que.empty()) {
		P p = que.top();
		que.pop();
		int now = p.second;
		if (dist[now] < p.first) {
			continue;
		}
		for (auto next_v : G[now]) {
			if (dist[next_v.to] > dist[now] + next_v.weight) {
				dist[next_v.to] = dist[now] + next_v.weight;
				que.push(P(dist[next_v.to], next_v.to));
			}
		}
	}

	vector<ll> r_dist(n + 1, INF);
	r_dist[1] = 0;
	que.push(P(0, 1));
	while (!que.empty()) {
		P p = que.top();
		que.pop();
		int now = p.second;
		if (r_dist[now] < p.first) {
			continue;
		}
		for (auto next_v : rG[now]) {
			if (r_dist[next_v.to] > r_dist[now] + next_v.weight) {
				r_dist[next_v.to] = r_dist[now] + next_v.weight;
				que.push(P(r_dist[next_v.to], next_v.to));
			}
		}
	}

	ll result = 0;
	for (int i = 1; i <= n; ++i) {
		if ((dist[i] == INF) || (r_dist[i] == INF)) {
			continue;
		}
		if (dist[i] + r_dist[i] <= t) {
			result = max(result, (t - dist[i] - r_dist[i]) * a[i]);
		}
	}

	cout << result << endl;

	return 0;
}

AC(Accepted=正しいプログラム)と判定されました。

最後に

辺の向きを逆にしたグラフを考慮することが、この問題のポイントでした。

引き続き ABC の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA