P2136 拉近距离
题面
题目背景
我是源点,你是终点。我们之间有负权环。 ——小明
题目描述
在小明和小红的生活中,有 个关键的节点。有 个事件,记为一个三元组 ,表示从节点 有一个事件可以转移到 ,事件的效果就是使他们之间的距离减少 。
这些节点构成了一个网络,其中节点 和 是特殊的,节点 代表小明,节点 代表小红,其他代表进展的阶段。所有事件可以自由选择是否进行,但每次只能进行当前节点邻接的。请你帮他们写一个程序,计算出他们之间可能的最短距离。
输入格式
第一行,两个正整数 。
之后 行,每行 个空格隔开的整数 。
输出格式
一行,一个整数表示他们之间可能的最短距离。如果这个距离可以无限缩小,输出Forever love
。
样例 #1
样例输入 #1
3 3
1 2 3
2 3 -1
3 1 -10
样例输出 #1
-2
提示
对于 数据,,。
对于 数据,,。
对于 数据,,,,保证从节点 到 有路径,从节点 到 有路径。
思路
怎么让小明和小红永远在一起呢?
考验阅读理解的时候来了。
大部分人都会和我想的一样,觉得这就是写个最短路顺便判下负环呗。
确实是这样,但是题目中有几个坑人的点。
首先就是事件的效果是使距离减少,所以边权要在原来的基础上取负。
其次,小明和小红不一定是谁靠近谁,所以可能是或者(这才是双向奔赴嘛),于是跑两遍最短路然后取,如果在这个过程中,发现了有负环,那就可以Forever love
了。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+7;
const int M=1e4+7;
int n,m,cnt;
struct edge
{
int to,nxt,d;
}e[M];
int dist[N];
int fir[N];
bool vis[N];
int l[N];
void add(int u,int v,int w)
{
e[++cnt].to=v;
e[cnt].nxt=fir[u];
e[cnt].d=w;
fir[u]=cnt;
}
void SPFA(int x)
{
for(int i=1;i<=n;i++)
{
l[i]=0;
dist[i]=INT_MAX;
vis[i]=false;
}
dist[x]=0;
queue<int> Q;
Q.push(x);
while(Q.size())
{
int now=Q.front();
Q.pop();
vis[now]=false;
for(int i=fir[now];i;i=e[i].nxt)
{
int v=e[i].to;
int dis=dist[now]+e[i].d;
if(dis<dist[v])
{
l[v]=l[now]+1;
if(l[v]>=n)
{
printf("Forever love");
exit(0);
}
dist[v]=dis;
if(!vis[v])
{
vis[v]=true;
Q.push(v);
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,-c);
}
SPFA(1);
int ans=dist[n];
SPFA(n);
ans=min(ans,dist[1]);
printf("%d",ans);
return 0;
}