Official

D - 最短避難経路 / Shortest Evacuation Route Editorial by physics0523


AWC0050-D とほぼ同じなので、 当該問題の解説 とは異なったアプローチで解きます。

問題文中の記述に従い、初期条件として以下を課す。

  • 都市 \(1\) が冠水していなければ、都市 \(1\) での所要時間は \(0\) 分である。
  • 都市 \(1\) が冠水していれば、都市 \(1\) での所要時間は \(T\) 分である。

そして、グラフの構築をうまく行うことを考えます。

  • 都市 \(U_i\) から都市 \(V_i\) に移動するのに \(W_i\) 分かかる。

ここに冠水のペナルティを課すことを考えます。つまり、

  • 都市 \(V_i\) が冠水していなければ、都市 \(U_i\) から都市 \(V_i\) に移動するのに \(W_i\) 分かかる。
  • 都市 \(V_i\) が冠水していれば、都市 \(U_i\) から都市 \(V_i\) に移動するのに \(W_i+T\) 分かかる。

直感的には、冠水している都市 \(V_i\) に入場する際に、辺の重みに追加して \(T\) のペナルティを課す感じです。
このように辺を張ることにすると、冠水の条件も含めてひとつの最短経路問題としてこの問題を解くことができます。

あとは、ダイクストラ法などを用いて最短経路問題を解けばよいです。

実装例 (C++):

#include<bits/stdc++.h>

using namespace std;

using ll=long long;
using pl=pair<ll,ll>;
using Graph=vector<vector<pl>>;

int main(){
  ll N,M,K,T;
  cin >> N >> M >> K >> T;
  vector<ll> u(M),v(M),w(M);
  for(ll i=0;i<M;i++){
    cin >> u[i] >> v[i] >> w[i];
    u[i]--; v[i]--;
  }
  vector<ll> wet(N,0);
  for(ll i=0;i<K;i++){
    ll g;
    cin >> g;
    wet[g-1]=T;
  }

  Graph g(N);
  for(ll i=0;i<M;i++){
    g[u[i]].push_back({v[i],w[i]+wet[v[i]]});
    g[v[i]].push_back({u[i],w[i]+wet[u[i]]});
  }

  vector<ll> d(N,4e18);
  priority_queue<pl,vector<pl>,greater<pl>> pq;
  d[0]=wet[0];
  pq.push({wet[0],0});
  while(!pq.empty()){
    auto od=pq.top(); pq.pop();
    if(d[od.second]!=od.first){continue;}

    for(auto &nx : g[od.second]){
      if(d[nx.first]>d[od.second]+nx.second){
        d[nx.first]=d[od.second]+nx.second;
        pq.push({d[nx.first],nx.first});
      }
    }
  }
  cout << d[N-1] << "\n";
  return 0;
}

posted:
last update: