【u251】心灵的抚慰

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

病毒问题解决后,神牛们的心灵久久不能平静。他可以从一个程序联想到一些相似的程序。比如从程序1联想到2,从2联想到4,从4联想到6,从6联想到9……就像搜索一样一步一步越陷越深。不过同一种联想他只会联想一次。比如1、2之间他进行了一次联想,那么他不会再重新联想1到2,或2到1。如果他刚开始时想到的程序能够经过联想若干次后联想回到原程序,那不就乱回来了吗?由于神牛马上就要开乱,请在1秒内告诉他,他需要想哪个程序,以便乱回来。 给出一些程序和他们互相联想的关系(如果两个程序A、B有联系,神牛可以从A联想到B,也可以从B联想到A,但A、B之间神牛最多联想一次),请告诉神牛他需要想哪个程序,以便在最短的时间内乱回来,并输出这个最短时间。

【输入格式】

第一行有两个正整数N,M,分别表示程序个数和有多少对程序可以被神牛直接互相联想。 以下M行,每行三个正整数,分别表示一种联想的两端的程序的编号(从1开始),以及进行这种联想所需要的最短时间(≤3500)。

【输出格式】

如果神牛无论如何都再也乱不回来了,输出“He will never come back.”。 如果神牛能够乱回来,请输出神牛会乱多长时间。

【数据规模】

对于100% 的数据,n≤250。

Sample Input1

4 3
1 2 10
1 3 20
1 4 30

Sample Output1

He will never come back.

【题目链接】:http://noi.qz5z.com/viewtask.asp?id=u251

【题解】


    for (int k = 1;k <= n;k++)
    {
        for (int i = 1;i <= k-1;i++)
            for (int j = i+1;j <= k-1;j++)
                mi = min(mi,dis[i][j]+w[j][k]+w[k][i]);
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= n;j++)
                dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
    }


mi即为最小环
最小环是基于floyd算法实现的;
因为当k层循环进行到第k层时,任意两点之间通过中间节点1..k-1得到的最短路已经求出来了;
则我们枚举包含节点k的最小环(且除了k号节点外这个环里的其他节点编号都小于k),即dis[i][j(i到j的最短路,注意i到j的最短路不会包括k),然后加上w[j][k]+w[k][i];这样就是一个环形了;然后取最小值,那么就能搞出最小环了;
这里的w数组之所以要另用一个数组是因为如果直接写dis[j][k]+dis[k][i];那么你不能预测j到k的路径或k到i的路径里面会不会包含dis[i][j]中经过的点;如果有这种情况那么就不能称之为环了;
还有就是

        for (int i = 1;i <= k-1;i++)
            for (int j = i+1;j <= k-1;j++)
                mi = min(mi,dis[i][j]+w[j][k]+w[k][i]);


这里的j层循环必须从i+1开始,不然会出现两个节点直接走过去然后又直接走回来的情况(而题目不允许这样);(题目所给的边是无向边);

【完整代码】

#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL long long

using namespace std;

const LL INF = 1e15;
const int MAXN = 300;

int n,m;
LL w[MAXN][MAXN],dis[MAXN][MAXN];

int main()
{
    //freopen("F:\\rush.txt","r",stdin);
    for (int i = 0;i <= 250;i++)
        for (int j = 0;j <= 250;j++)
            w[i][j]=dis[i][j] = INF;
    cin >>n >> m;
    for (int i = 1;i <= m;i++)
    {
        int x,y;LL z;
        cin >> x >> y >> z;
        w[x][y] = z;
        w[y][x] = z;
        dis[x][y] = z;
        dis[y][x] = z;
    }
    LL ans = INF;
    for (int k = 1;k <= n;k++)
    {
        for (int i = 1;i <= k-1;i++)
            for (int j = i+1;j <= k-1;j++)
                ans = min(ans,dis[i][j]+w[j][k]+w[k][i]);
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= n;j++)
                dis[i][j] = min (dis[i][j],dis[i][k]+dis[k][j]);
    }
    if (ans >= INF)
        puts("He will never come back.");
    else
        cout << ans <<endl;
    return 0;
}
posted @ 2017-10-04 18:45  AWCXV  阅读(89)  评论(0编辑  收藏  举报