用spfa 算法求關於有負權邊的最短路。
每次從隊列中取出一個節點X,遍歷與X相通的Y節點,查詢比對 Y的長度 和 X的長度+ X與Y的長度
如果X的長度+ X與Y的長度 > Y的長度,說明需要更新操作。
1).存入最短路。
2).由於改變了原有的長度,所以需要往後更新,與這個節點相連的最短路。(即:判斷下是否在隊列,在就不用重複,不在就加入隊列,等待更新)。
3).在這期間可以記錄這個節點的進隊次數,判斷是否存在負環。
4.直到隊空。
判斷有無負環:如果某個點進入隊列的次數超過N次則存在負環。
給出spfa 模;板
bool spfa(int s){
queue<int> q;
for(int i=0;i<=n;i++)
ksum[i] = vis[i] = 0,dis[i] = INF;
dis[s] = 0,vis[s] = 1,q.push(s);
while(q.size()){
int u = q.front();
q.pop();
vis[u] = 0; //這裏需要注意,因爲存在負權,spfa每個節點需要重複入隊
for(int i = head[u];~i;i = nex[i]){
int v = to[i],w=edge[i];
if(dis[u] + w < dis[v]){
dis[v] = dis[u] + w;
if(!vis[v]){
q.push(v); vis[v] = 1;
if(++ksum[v]> n){
return true;
}
}
}
}
}
return false;
}
給出模板題:http://poj.org/problem?id=3259
//#include<bits/stdc++.h>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N =3e3;
const int INF = 1e9;
int to[N<<1],nex[N<<1],edge[N<<1];
int n,m,k,cnt;
int dis[N],vis[N],ksum[N],head[N];
void add(int x,int y,int w){
to[++cnt]= y;
nex[cnt]= head[x];
edge[cnt] = w;
head[x] = cnt;
}
bool spfa(int s){
queue<int> q;
for(int i=0;i<=n;i++)
ksum[i] = vis[i] = 0,dis[i] = INF;
dis[s] = 0,vis[s] = 1,q.push(s);
while(q.size()){
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u];~i;i = nex[i]){
int v = to[i],w=edge[i];
if(dis[u] + w < dis[v]){
dis[v] = dis[u] + w;
if(!vis[v]){
q.push(v); vis[v] = 1;
if(++ksum[v]> n){
return true;
}
}
}
}
}
return false;
}
int main(){
int t;scanf("%d",&t);
while(t--){
cnt = 0;
memset(head,-1,sizeof head);
scanf("%d%d%d",&n,&m,&k);
for(int i = 1,x,y,w;i <= m; i ++){
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
for(int i = 1,u,v,w;i <= k; i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,-w);
}
if(spfa(1)) printf("YES\n");
else printf("NO\n");
}
return 0;
}
再給一題簽到題:https://nanti.jisuanke.com/t/41305
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
const int INF = 2e9;
int to[N<<1],nex[N<<1];ll edeg[N<<1];
int n,m,k,cnt;
int head[N];
bool vis[N];
ll dis[N];
void add(int x,int y,int w){
to[++cnt]= y;
nex[cnt]= head[x];
edeg[cnt] = w;
head[x] = cnt;
}
void spfa(int s){
queue<int> q;
for(int i=0;i<=n;i++)
vis[i] = false,dis[i] = INF;
vis[s]=true,dis[s] = 0,q.push(s);
while(q.size()){
int u = q.front();
q.pop();
vis[u] = false; //這裏需要注意,因爲存在負權,spfa每個節點需要重複入隊
for(int i=head[u];~i;i = nex[i]){
int v = to[i];
if(dis[v] > dis[u]+ edeg[i]){
dis[v] = dis[u] + edeg[i];
if(!vis[v]){
q.push(v);
vis[v] = true;
}
}
}
}
}
int main(){
int t;scanf("%d",&t);
while(t--){
cnt = 0;
memset(head,-1,sizeof head);
scanf("%d%d",&n,&m);
for(int i = 1,u,v,w;i <= m;i ++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
for(int i=1;i<=6;i++){
int s,t;scanf("%d%d",&s,&t);
spfa(t);
printf("%lld\n",-dis[s]);
add(s,t,-dis[s]);
}
}
return 0;
}