【洛谷 2136】拉近距离
题目背景
我是源点,你是终点。我们之间有负权环。 ——小明
题目描述
在小明和小红的生活中,有N个关键的节点。有M个事件,记为一个三元组(Si,Ti,Wi),表示从节点Si有一个事件可以转移到Ti,事件的效果就是使他们之间的距离减少Wi。
这些节点构成了一个网络,其中节点1和N是特殊的,节点1代表小明,节点N代表小红,其他代表进展的阶段。所有事件可以自由选择是否进行,但每次只能进行当前节点邻接的。请你帮他们写一个程序,计算出他们之间可能的最短距离。
输入格式
第1行,两个正整数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。
对于全部数据,N<=1000,M<=10000,|Wi|<=100,保证从节点1到N有路径。
题解:spfa还没死,继续spfa肝题
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> using namespace std; const int N=20002; const string out="Forever love"; int cnt,x,y,z,n,m,ok[N]; struct node{ int next; int to; int val; }e[N]; int head[N],dis[N],vis[N]; void add(int x,int y,int z){ e[++cnt].val=z; e[cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } int flag=0; void spfa(int jjj){ queue<int>q; memset(dis,0x3f,sizeof(dis)); q.push(jjj); vis[jjj]=1; dis[jjj]=0; while(!q.empty()){ x=q.front(); q.pop(); vis[x]=0; if(ok[x]>n){ cout<<out<<endl;exit(0); flag=1; return ; } for(int i=head[x];i;i=e[i].next){ y=e[i].to; if(dis[y]>dis[x]+e[i].val){ dis[y]=dis[x]+e[i].val; if(vis[y]==0) { q.push(y); ok[y]++; vis[y]=1; } } } } return ; } int main(){ freopen("2136.in","r",stdin); freopen("2136.out","w",stdout); scanf("%d %d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d %d %d",&x,&y,&z); add(x,y,-z); } if(flag==1) return 0; spfa(1); int s1=dis[n]; spfa(n); int s2=dis[1]; printf("%d",min(s1,s2)); return 0; }