SRM 675 Div2 Medium ShortestPathWithMagic
TopCoder Statistics - Problem Statement
- ここ1ヶ月くらいサボりまくっていて久しぶりの SRM だった。
- 本番ナップザック的に DP でやれるんじゃないか?と思いつつも、i < j のとき j -> i へ移動するほうが最短な場合もあるし、だめかなーと思って幅優先っぽい手法で解いた。
- 本番最後の REP(i,k+1) が REP(i,k) にするというバグで時間を食ってしまった...。
class ShortestPathWithMagic { public: double getTime(vector <string> dist, int k) { int n = dist.size(); const double inf = (1<<30); vector<vector<double>> d(n,vector<double>(k+1,inf)); #define cost(x,y) (dist[x][y]-'0') queue<tuple<int,int,double>> que; que.emplace(0,k,0); while ( !que.empty() ) { double t; int kk; int x; tie(x,kk,t) = que.front(); que.pop(); REP(i,n) { if (x == i) continue; if ( kk > 0 && t+cost(x,i)/2.0 < d[i][kk-1] ) { d[i][kk-1] = t+cost(x,i)/2.0; que.emplace(i, kk-1, t+cost(x,i)/2.0); } if ( t+cost(x,i) < d[i][kk] ) { d[i][kk] = t+cost(x,i); que.emplace(i, kk, t+cost(x,i)); } } } double ret = inf; REP(i,k+1) ret = min(d[1][i],ret); return ret; } };
- 他の人のコードを見るに普通に DP で解けるのでそっちも実装してみた。普通に逆方向も見る全探索にすればいいだけだった。
class ShortestPathWithMagic { public: double getTime(vector <string> dist, int k) { int n = dist.size(); const double inf = (1<<30); vector<vector<double>> d(n,vector<double>(k+1,inf)); #define cost(x,y) (dist[x][y]-'0') // Warshallfloyd で一旦最短経路を求めておく vector<vector<double>> g(n,vector<double>(n,inf)); REP(i,n) REP(j,n) g[i][j] = cost(i,j); REP(l,n) REP(i,n) REP(j,n) g[i][j] = min(g[i][j], g[i][l]+g[l][j]); // DP で解く // dp[i][k] := 0 -> i まで到達するとき potion の使用量が k であるときの最短経路長 vector<vector<double>> dp(n,vector<double>(k+1,inf)); dp[0][0] = 0.0; // 全探索 REP(kk,k+1) { // j を経由して i に行くときを計算 REP(i,n) REP(j,n) dp[i][kk] = min(dp[i][kk], dp[j][kk] + g[j][i]); if ( kk == k ) break; REP(i,n) REP(j,n) dp[i][kk+1] = min(dp[i][kk+1], dp[j][kk] + cost(j,i)/2.0); } double ret = inf; REP(kk,k+1) ret = min(ret,dp[1][kk]); return ret; } };