優先度付き幅優先探索(最小コストの算出)
内容
よくある最短経路や最小コストを求める問題。
ダイクストラの拡張例みたいなもの。
生成された状態空間の中でもっともコストの小さい状態を抽出。
抽出された状態がゴールならそれが最小。
抽出された状態から次の状態を状態空間に挿入していく。
集合から最小を抽出するので、set
ただ、setの方がタイピングがしやす(ry
実装例
#include <iostream> #include <set> #include <algorithm> using namespace std; #define REP(i,n) for(int i=0;i<n;i++) #define rep(n) REP(i,n) int n,m,l; typedef pair<int,int> S; // 残りのお金,現在地 typedef pair<int,S> pp; // 襲われた人数を優先 const int INF = 10000000; const int MXN = 102; bool visited[MXN][MXN]; int cost[MXN][MXN]; int damage[MXN][MXN]; int main() { while(cin>>n>>m>>l&&(n||m||l)) { REP(i,MXN) REP(t,MXN){ cost[i][t]=INF; damage[i][t]=INF; visited[i][t]=false; } int a,b,d,e; rep(m) { cin>>a>>b>>d>>e; // 隣接行列で表現(*双方向移動可) cost[a][b] = d; damage[a][b] = e; cost[b][a] = d; damage[b][a] = e; } set<pp> s; // 状態の集合 s.insert( pp(0,S(l,1)) ); // 初期状態 損害=0,残り=l,場所=1 while(!s.empty()) { pp p = *s.begin(); s.erase(s.begin()); // 最小を取り出す int vv = (p.second).second; // 場所 int cc = (p.second).first; // 残りの資金 int dd = (p.first); // 損害 if( vv == n ){ cout<<dd<<endl; break; } if( visited[vv][cc] ) continue; else visited[vv][cc]=true; rep(n+1) // 次の状態を生成 { if( cost[vv][i] == INF ) continue; // 道がない場合は除く if( cost[vv][i]<=cc ) s.insert( pp(dd,S(cc-cost[vv][i],i)) ); // 支払う場合 s.insert( pp(dd+damage[vv][i],S(cc,i)) ); // 支払わない場合 } } } return 0; }
次に遷移可能な状態をすべて生成。
今まで生成した状態と、今作った状態の全てからまた最小を探して繰り返し。