spfa求最短路
与Dijkstra的堆优化版 极其相似。
spfa:队列(类似宽搜);正负边权都能处理(优);易被卡成 O ( n m ) O(nm) O(nm)
Dijkstra(堆优化):优先队列(小根堆),类似宽搜。只能处理边权为正的图。 O ( m l o g n ) O(mlogn) O(mlogn)
//同Dijkstra的堆优化版
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
int h[N],e[N],w[N],ne[N],idx;
int dis[N];
bool st[N];
int n,m;
void add(int a, int b, int c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void spfa(){
memset(dis,0x3f,sizeof(dis));
dis[1] = 0;
queue<int> q;
q.push(1);//将1结点入栈
st[1] = true;
while(q.size()){
int t = q.front();
q.pop();
st[t] = false;
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(dis[j] > dis[t] + w[i]){
dis[j] = dis[t] + w[i];
if(!st[j]){
q.push(j);
st[j] = true;
}
}
}
}
if(dis[n] > 0x3f3f3f3f/2) puts("impossible");
else printf("%d\n",dis[n]);
}
int main(){
scanf("%d%d",&n,&m);
memset(h, -1, sizeof(h));
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
spfa();
return 0;
}
spfa判断负环
需要反复理解
。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 2e3 + 10, M = 1e4 + 10;
int h[N], e[M],ne[M],w[M],idx;
int dis[N];
bool st[N];
int n,m;
int cnt[N];
void add(int a, int b , int c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
bool spfa(){
// memset(dis, 0x3f,sizeof(dis));不算很理解为啥不赋值
//可能是因为全局变量为0,若w[i]为负,则dis[j]依旧大于dis[t] + w[i]。
//就能够对cnt进行更新,判断是否点重复,即负环。
// dis[1] = 0;
queue<int> q;
for(int i = 1; i <= n; i++){
q.push(i);
st[i] = true;
}
while(q.size()){
int t = q.front();
q.pop();
st[t] = false;
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(dis[j] > dis[t] + w[i]){
dis[j] = dis[t] + w[i];
cnt[j] = cnt[t] + 1;//不算很理解
if(cnt[j] >= n) return true;
if(!st[j]){
q.push(j);
st[j] = true;
}
}
}
}
return false;
}
int main(){
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
if(spfa()) puts("Yes");
else puts("No");
// spfa();
return 0;
}