最短回路SPFAアルゴリズム(隣接テーブルにより実現)
4477 ワード
適用範囲:与えられた図には負の重みエッジが存在し、Dijkstraのようなアルゴリズムは武力を使う場所がなく、Bellman-Fordアルゴリズムの複雑さが高すぎて、SPFAアルゴリズムが役に立ちました.重み付け図Gには負の重み回路が存在しないこと,すなわち最短経路は必ず存在することを約束する.もちろん,このアルゴリズムを実行する前にトポロジーソートを行い,負の重みループが存在するか否かを判断することができるが,これは我々の議論の重点ではない.
主な考え方:図を隣接テーブルedges[mxan]で格納し、(もちろん隣接マトリクスでもいい)、その後SPFA操作を行い、dis[maxm]配列でソースポイントから他のポイントへの最短ルートを記録し、vis[maxm]配列でどの点が通過したかをマークし、que[maxm]キューで現在緩和すべき点を維持し、毎回先頭を取って操作する.キューが空になるまで、キューの先頭から拡張されたポイントが順番にキューの最後に追加されます.
実装方法:
キューを作成します.最初はキューに開始点しかありません.開始点からすべての点までの最短パスを記録するテーブルを作成します(テーブルの初期値は極大値に割り当てられ、そのポイントから彼自身のパスは0に割り当てられます).その後、リラックス操作を実行し、キューにある点を開始点としてすべての点の最短ルートにリフレッシュし、リフレッシュに成功し、リフレッシュされた点がキューにない場合は、その点をキューの最後に追加します.キューが空になるまで繰り返します.
負ループの有無判断:あるポイントがキューに入る回数がN回を超えると負ループが存在する(SPFAが負ループ付きの図を処理できない)
以下にコードを貼ります.
主な考え方:図を隣接テーブルedges[mxan]で格納し、(もちろん隣接マトリクスでもいい)、その後SPFA操作を行い、dis[maxm]配列でソースポイントから他のポイントへの最短ルートを記録し、vis[maxm]配列でどの点が通過したかをマークし、que[maxm]キューで現在緩和すべき点を維持し、毎回先頭を取って操作する.キューが空になるまで、キューの先頭から拡張されたポイントが順番にキューの最後に追加されます.
実装方法:
キューを作成します.最初はキューに開始点しかありません.開始点からすべての点までの最短パスを記録するテーブルを作成します(テーブルの初期値は極大値に割り当てられ、そのポイントから彼自身のパスは0に割り当てられます).その後、リラックス操作を実行し、キューにある点を開始点としてすべての点の最短ルートにリフレッシュし、リフレッシュに成功し、リフレッシュされた点がキューにない場合は、その点をキューの最後に追加します.キューが空になるまで繰り返します.
負ループの有無判断:あるポイントがキューに入る回数がN回を超えると負ループが存在する(SPFAが負ループ付きの図を処理できない)
以下にコードを貼ります.
#include
using namespace std;
#define INF 0x7fffffff
const int maxn = 100005;
const int maxm = 5005<<1;
struct Data{
int x;
int value;
int next;
}edges[maxm];
int first[maxm], dis[maxm], que[maxm], vis[maxm];
int N, M;
void read_edges(){
cin >> N >> M;
for(int i = 1; i <= N; i++){
first[i] = -1;
vis[i] = 0;
dis[i] = INF;
}
for(int e = 1, u, v, w; e <= M; e++){
cin >> u >> v >> w;
edges[e].x = v;
edges[e].value = w;
edges[e].next = first[u];
first[u] = e;
}
}
void SPFA(){
int start = 1; // ,
vis[start] = 1;
dis[start] = 0;
int head = 0, tail = 1, cur;
que[tail] = start; //
while(head != tail){
head = (head + 1) % 1000; //head
//%1000 ,
cur = que[head];
vis[cur] = 0; //
int k = first[cur]; // ,
while(k != -1){
if(dis[cur] > dis[edges[k].x] + edges[k].value) //
dis[cur] = dis[edges[k].x] + edges[k].value;
if(!vis[edges[k].x]){
vis[edges[k].x] = 1;
tail = (tail + 1) % 1000;
que[tail] = edges[k].x; //
}
k = edges[k].next; //
}
}
// cout << dis[N] << endl;
}
int main(){
read_edges();
SPFA();
return 0;
}