适用于有负权边的情况
时间复杂度O(mn)
dist[b] = min(dist[b], dist[a] + w)
只有当dist[a] 有变小的可能时, dist[b]才有变小的可能
通过队列进行更行可能会变小的路径
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
//邻接表存图
const int N = 100010;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
bool vis[N];
void add(int a, int b, int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
int n;
int spfa(){
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
queue<int>q;
q.push(1);
vis[1] = true;
while(!q.empty()){
int t = q.front();
q.pop();
// if(vis[t]) continue;
vis[t] = false;
//找到t的临边进行更新
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i]; // 当前的这个点
if(dist[j] > dist[t] + w[i]){
dist[j] = dist[t] + w[i];
if(!vis[j]){
q.push(j);
vis[j] = true;
}
}
}
}
return dist[n];
}
int main(){
int m;
cin>>n>>m;
int x, y, z;
memset(h, -1, sizeof h);
for(int i = 0; i < m; i++){
cin>>x>>y>>z;
add(x,y,z);
}
int ans = spfa();
if(ans > 0x3f3f3f3f/2){
cout<<"impossible" << '\n';
}else cout <<ans << '\n';
return 0;
}
spfa - 判断是否有负环
通过cnt[]数组进行判断
cnt[]用来判断最短路的边数,当边数 >= n 说明在负环这里一直循环。
需要注意的是 负环不一定从1开始 ,即每个点都是起点,所以最初需要把每个点都加进去。
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
//邻接表存图
const int N = 100010;
int h[N], w[N], e[N], ne[N], idx;
int dist[N] ,cnt[N];
bool vis[N];
void add(int a, int b, int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
int n;
bool spfa(){
memset(dist, 0x3f, sizeof dist);
// dist[1] = 0;
queue<int>q;
for(int i = 1; i <= n; i++){
q.push(i);
vis[i] = true;
cnt[i] = 0;
}
while(!q.empty()){
int t = q.front();
q.pop();
// if(vis[t]) continue;
vis[t] = false;
//找到t的临边进行更新
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i]; // 当前的这个点
if(dist[j] > dist[t] + w[i]){
dist[j] = dist[t] + w[i];
cnt[j] = cnt[t] + 1;
if(cnt[j] >= n){
return true;
}
if(!vis[j]){
q.push(j);
vis[j] = true;
}
}
}
}
return false;
}
int main(){
int m;
cin>>n>>m;
int x, y, z;
memset(h, -1, sizeof h);
for(int i = 0; i < m; i++){
cin>>x>>y>>z;
add(x,y,z);
}
bool ans = spfa();
if(ans){
cout<<"Yes" << '\n';
}else cout <<"No" << '\n';
return 0;
}