Acwing1168. 简单单源最短路径问题
注意事项:该题要调用两次spfa,第一次判断是否有负环,对于判断是否有负环,我们就是将每个节点都放进去,判断是否存在以这些节点开始或参与的环,定义一个
c
n
t
[
i
]
cnt[i]
cnt[i]表示节点i出现的次数,如果大于等于
n
n
n,说明存在负环,直接return即可。
第二次调用就是单纯的求以
s
s
s为起始节点到各节点的距离
代码如下:
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define ll long long
#define pii pair<int,int>
using namespace std;
const int N = 1010, M = 1e5+10;
const int INF = 0x3f3f3f3f;
int n, m, s;
int e[M], ne[M], w[M], head[N], idx;
int cnt[N], dis[N];
bool vim[N];
queue<int> q;
void add(int a, int b, int c){
e[++idx] = b;
w[idx] = c;
ne[idx] = head[a];
head[a] = idx;
}
bool spfa(){
memset(dis, 0x3f, sizeof dis);
memset(vim, 0, sizeof vim);
memset(cnt, 0, sizeof cnt);
dis[q.front()] = 0;
while(!q.empty()){
int t = q.front();q.pop();
vim[t] = true;
for(int i = head[t];~i;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(vim[j]){
q.push(j);
vim[j] = false;
}
}
}
}
return false;
}
int main(){
ios;
memset(head, -1, sizeof head);
cin >> n >> m >> s;
while( m-- ){
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
for(int i = 1;i <= n;i++)q.push(i);
if(spfa()){
cout << "-1\n";
return 0;
}
queue<int> qq;
q = qq;
q.push(s);
spfa();
for(int i = 1;i <= n;i++){
cout << dis[i] << "\n";
// if(dis[i] == INF)cout << "NoPath\n";
// else cout << dis[i] << "\n";
}
return 0;
}