题目背景
我是源点,你是终点。我们之间有负权环。 ——小明
题目描述
在小明和小红的生活中,有 N 个关键的节点。有 M 个事件,记为一个三元组(Si,Ti,Wi),表示从节点 Si 有一个事件可以转移到 Ti,事件的效果就是使他们之间的距离减少 Wi。
这些节点构成了一个网络,其中节点 1 和 N 是特殊的,节点 1 代表小明,节点 N 代表小红,其他代表进展的阶段。所有事件可以自由选择是否进行,但每次只能进行当前节点邻接的。请你帮他们写一个程序,计算出他们之间可能的最短距离。
输入格式
第一行,两个正整数N,M。
之后 M 行,每行 3 个空格隔开的整数 Si,Ti,Wi。
输出格式
一行,一个整数表示他们之间可能的最短距离。如果这个距离可以无限缩小,输出
Forever love
。输入输出样例
输入 #1复制
3 3 1 2 3 2 3 -1 3 1 -10输出 #1复制
-2说明/提示
对于20% 数据,N≤10,M≤50。
对于50% 数据,N≤300,M≤5000。
对于100% 数据,1≤N≤10^3,1≤M≤10^4,∣Wi∣≤100,保证从节点 1 到 2…N 有路径,从节点 N 到 1…N−1 有路径。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,suc=1;
int dis[1000010];//存距离
bool vis[1000010];//存这个点是否搜过
int cnt[1000010];//存走的是第几次
vector<pair<int,int>> e[1000010];
bool spfa(int x){
for(int i = 1;i<=n;i++){
dis[i]=1e18;
vis[i]=0;
cnt[i]=0;//初始化
}
queue<int> q;
q.push(x);
dis[x]=0;
vis[x]=1;
while(q.size()){
int now=q.front();
q.pop();
vis[now]=0;
for(auto t:e[now]){
int a=t.first,b=t.second;
if(dis[a]>dis[now]-b){
cnt[a]=cnt[now]+1;
dis[a]=dis[now]-b;
if(cnt[a]>=n){//当走>=n次时,说明有负环
//因为当有负环时环的边权和为负数,dis会减小,就会一直更新一直走
suc=0;//记录一下有负环,可以无限缩小
return false;
}
if(vis[a]==0){
vis[a]=1;
q.push(a);
}
}
}
}
return true;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i<=m;i++){
int s,t,w;
scanf("%d%d%d",&s,&t,&w);
e[s].push_back({t,w});
}
//因为是单向的,所以要搜两遍
spfa(1);//从小明搜
int a=dis[n];//从小明搜的最短距离
spfa(n);//从小红搜
int b=dis[1];//从小红搜的最短距离
if(suc==0) printf("Forever love");//如果suc==0说明上面判断出来有负环,可以无限缩小
else printf("%d",min(a,b));//否则输出最短距离
return 0;
}