SoundHound Inc. Programming Contest 2018 -Masters Tournament- D - Saving Snuuk(400)
概要
n頂点m辺の連結無向グラフが与えられ、各辺には2種類のコスト(コストA, コストBと分類)が与えられる。
頂点sから頂点tに移動するコストを考える。このとき頂点iを選ぶ。すると頂点sから頂点iまではコストAがかかり、頂点iから頂点tまではコストBがかかるとする。なお、選ぶ頂点にはs, tも含まれる。
0, 1, ..., n-1の各整数について次の問いに答えよ。
- 整数iについて、頂点番号(1-indexed)がiより大きい頂点を選んでコストを切り替える場合、かかるコストの最小値を求めよ。出力はコストの最小値がaであるとき、10^15-aとして出力せよ。
制約
2 ≦ n, m ≦10^5
方針
各頂点iについて、コストAベースのsからiまでの最短距離d1(i)と、コストBベースのtからiまでの最短距離d2(i)をダイクストラ法で求める。
あとは大きい方の整数から最短距離を考えてゆけばよい。
つまり、下記の通り。
整数n-1については、n-1で切り替えるしかないので、n-1の最短距離をd(n-1)とすると、d(n-1) = d1(n-1) + d2(n-1)で確定する。
整数n-2については、n-1で切り替えるかn-2で切り替えるかが選択できるので、d(n-2) = min(d(n-1), d1(n-2) + d2(n-2))。
整数n-3については、n-1, n-2, n-3の切り替えが選択できる。d(n-3) = min(d(n-2), d1(n-3) + d2(n-3))。
...
解答
Submission #2816212 - SoundHound Inc. Programming Contest 2018 -Masters Tournament-
#include <bits/stdc++.h> #define FOR(i,a,b) for(int i=(a);i<(b);i++) #define rep(i,n) FOR(i,0,n) #define RFOR(i,a,b) for(int i=(a)-1;i>=(b);i--) #define rrep(i,n) RFOR(i,n,0) using namespace std; typedef long long ll; typedef unsigned long long ull; // dijkstra struct edge {ll to, cost;}; typedef pair<ll, ll> P; // firstはsからの最短距離, secondは頂点の番号 const ll INF = 1e15; void dijkstra(vector<edge> g[], vector<ll>& d, ll s){ d[s] = 0; priority_queue<P,vector<P>,greater<P> > que; que.push(P(0,s)); while(!que.empty()){ P p = que.top(); que.pop(); ll v = p.second; if(d[v] < p.first) continue; //後から最短パスが見つかった場合、先にqueに入っているものはここではじかれる for(ll i = 0; i < g[v].size(); i++){ edge e= g[v][i]; if(d[e.to] > d[v] + e.cost){ d[e.to] = d[v] + e.cost; que.push(P(d[e.to], e.to)); } } } } int main() { cin.tie(0); ios::sync_with_stdio(false); ll n, m, s, t; cin >> n >> m >> s >> t; s--; t--; vector<edge> g1[n]; vector<edge> g2[n]; rep(i, m){ ll u, v, a, b; cin >> u >> v >> a >> b; u--; v--; g1[u].push_back((edge){v, a}); g1[v].push_back((edge){u, a}); g2[u].push_back((edge){v, b}); g2[v].push_back((edge){u, b}); } vector<ll> d1(n, INF); vector<ll> d2(n, INF); dijkstra(g1, d1, s); dijkstra(g2, d2, t); // rep(i, n) cout << d1[i] << (i == n-1 ? "\n" : ","); // rep(i, n) cout << d2[i] << (i == n-1 ? "\n" : ","); ll ans[n]; rep(i, n) ans[i] = d1[i] + d2[i]; rrep(i, n-1) ans[i] = min(ans[i], ans[i+1]); // rep(i, n) cout << ans[i] << (i == n-1 ? "\n" : ","); rep(i, n) cout << (1000000000000000 - ans[i]) << endl; }