洛谷 P2136 拉近距离 题解

P2136 拉近距离

题目背景

我是源点,你是终点。我们之间有负权环。 ——小明

题目描述

在小明和小红的生活中,有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来判断负环的题目
SPFA判负环详见这篇博客
这里

【题目分析】

两个人之间能够到达并且缩短的距离最大化
这不就成了最长路了吗?
完全可以将数前面加个负号变为相反数
这样就可以跑最短路了
负环怎么判断?
当然是SPFA

【不完整思路】

知道了上面两点就很好办了
插入的时候转化为相反数
然后构建邻接矩阵
从1开始跑SPFA
如果有负环那就返回输出Forever love然后结束程序
不然那就输出1到n的最短距离
然后发现只有90分
是什么情况呢?

【最终思路】

这是单向路
所以不只有1能够向n跑,n也可以向1跑
所以两边SPFA
一遍 从1开始,
一遍 从n开始,
比较1到n和n到1这两条路那一条更短就输出
注意一下只要这两个方向有一个能够出现负环
那就输出Forever love
因为负环就是最短的体现

【完整代码】

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define int long long
using namespace std;
const int Max = 10004;
const int M = 1002;
struct node
{
    int y,ne,z;
}a[Max];
int sum = 0;
int n,m;
int head[M];

void add(int x,int y,int z)
{
    a[++ sum].y = y;
    a[sum].ne = head[x];
    a[sum].z = z;
    head[x] = sum;
}

int use[M],d[M],cnt[M];
bool SPFA(int acioi)
{
    queue<int>q;
    for(register int i = 1;i <= n;++ i)
        d[i] = 99999999;
    d[acioi] = 0;
    q.push(acioi);
    while(!q.empty())
    {
        int x = q.front();
        q.pop();use[x] = false;
        for(register int i = head[x];i != 0;i = a[i].ne)
        {
            int y = a[i].y;
            if(d[y] > d[x] + a[i].z)
            {
                d[y] = d[x] + a[i].z;
                cnt[y] = cnt[x] + 1;
                if(cnt[y] > n)
                    return false;
                if(use[y] == false)
                {
                    use[y] = true;
                    q.push(y);
                }
            }
        }
    }
    return true;
}

signed main()
{
    scanf("%lld%lld",&n,&m);
    int s,t,w;
    for(register int i = 1;i <= m;++ i)
    {
        scanf("%lld%lld%lld",&s,&t,&w);
        add(s,t,-w);
    }
    int MM;
    if(SPFA(1) == false)
    {
        cout << "Forever love" << endl;
        return 0;
    }
    MM = d[n];
    memset(use,false,sizeof(use));
    memset(cnt,0,sizeof(cnt));
    if(SPFA(n) == false)
    {
        cout << "Forever love" << endl;
        return 0;
    }
    cout << min(MM,d[1]) << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/acioi/p/11694335.html