F - Pure ~ワーシャルフロイド・最小閉路・経路(パス)復元~

解法

補足

  • N=1000で通るのか?ギリギリ通る(事前にワーシャルフロイドだけして提出 1000msなのでギリギリ通ることを確認)
    • N=1000
    • O(N3)のワーシャルフロイド。ここが計算量のボトルネックで、実行時間は1100ms. よって109は超シンプルでギリギリ通る
  • uからvに行き、vからuに行くと最小のサイクル
    • そういうu, vをO(N2)の全探索で探す。見つけた後はpath(u, v), path(v, u)を求めればよい
  • path(u, v)はbfsで求めた。配列revで足跡を保存
    • (変数名はpreでもいいかも)

f:id:peroon:20191001042803p:plain

(revを用いた)経路復元

// iからjへの経路
// N : 頂点数
// G : graph (vector<vector<int>>)
VI get_path(ll i, ll j){
  VI rev(N, -1); // どこから来たかを保存
  vector<bool> visited(N, false);

  // bfsして各頂点への最短路を求める
  queue<ll> que;
  que.push(i);
  visited[i] = true;
  while(!que.empty()){
    ll from = que.front(); que.pop();
    for(ll to : G[from]){
      if(visited[to]) continue;
      visited[to] = true;
      rev[to] = from; // どこから来たかを保存
      que.push(to);
    }
  }
  VI ret;
  ret.push_back(j); // 終点から足していく
  
  ll now = j;
  while(true){
    ret.push_back(rev[now]);
    now = rev[now];
    if(now==i) return ret;
  }
}