https://atcoder.jp/contests/past202010-open/tasks/past202010_j
前提知識
解説
https://atcoder.jp/contests/past202010-open/submissions/21472629
ダイクストラをするが、特殊なグラフ形成をする必要がある。
ダイクストラをよく知らずにこの問題を解くのは難しいので、先にダイクストラをマスターすることをお勧めする。
ワープが無ければ
普通にダイクストラするだけ。
これでまずはグラフを作る。
ワープをどうするか
真面目にワープの辺を貼ると、タイプAの全ての頂点からタイプBの全ての頂点にコストXabの辺を貼るみたいなことを
たくさんやらなきゃいけないので、明らかに数が多い。
そこで、タイプAからタイプBへの遷移を
タイプAの頂点 -0-> タイプA入まとめ集合 -Xab-> タイプB出まとめ集合 -0-> タイプBの集合
とやると任意のタイプAからタイプBへの移動を網羅的に表現できる。
これを他の全てのワープについて実装して、ダイクストラすれば答えが得られる。
int N, M, Xab, Xac, Xbc; string S; vector<pair<int, int>> E[101010]; enum { A, B, C, A2, B2, C2 }; //--------------------------------------------------------------------------------------------------- template<typename T> using min_priority_queue = priority_queue<T, vector<T>, greater<T>>; int vis[101010]; void dijk(int s, vector<ll>& D) { rep(i, 0, N + 12) D[i] = infl; rep(i, 0, N + 12) vis[i] = 0; min_priority_queue<pair<ll, int>> que; D[s] = 0; que.push({ 0, s }); while (!que.empty()) { auto q = que.top(); que.pop(); ll cst = q.first; int cu = q.second; if (vis[cu]) continue; vis[cu] = 1; fore(p, E[cu]) { ll cst2 = cst + p.second; int to = p.first; if (chmin(D[to], cst2)) que.push({ D[to], to }); } } } //--------------------------------------------------------------------------------------------------- void _main() { cin >> N >> M >> Xab >> Xac >> Xbc >> S; 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 }); } rep(i, 0, N) { if (S[i] == 'A') { E[i].push_back({ N + A, 0 }); E[N+A2].push_back({ i, 0 }); } else if (S[i] == 'B') { E[i].push_back({ N + B, 0 }); E[N + B2].push_back({ i, 0 }); } else if (S[i] == 'C') { E[i].push_back({ N + C, 0 }); E[N + C2].push_back({ i, 0 }); } } E[N + A].push_back({ N + B2, Xab }); E[N + A].push_back({ N + C2, Xac }); E[N + B].push_back({ N + A2, Xab }); E[N + B].push_back({ N + C2, Xbc }); E[N + C].push_back({ N + A2, Xac }); E[N + C].push_back({ N + B2, Xbc }); vector<ll> dst(N + 12); dijk(0, dst); cout << dst[N - 1] << endl; }