ACM模版

描述

题解

先使用Floyd扫描一遍,判断连通性,然后使用BellmanFord算法跑跑就可以了。

这里一开始有些懵逼,搞不懂为啥要用Floyd,因为只求1~n的连通性不必要用Floyd啊,还那么慢,后来仔细看发现,后边判断是否有正环时还要使用到其他点之间的连通性,所以呢,Floyd是很有必要的。通常用BellmanFord算法时是求最短路,所以第三部分是判断是否有负环,但是这里我们是判断最长路,所以对应判断是否有正环,有正环并且该点与第n点连通,就输出winnable~~~没有正环时也是可以的,只要能够到达就行。

代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int MAXN = 105;
const int MAXM = MAXN * MAXN / 2;
const int INF = 0x3f3f3f3f;

int dist[MAXN];
int g[MAXN];
int map[MAXN][MAXN];

struct edge
{
    int x, y;
} Edge[MAXM];

int n, m;

void floyd()
{
    for (int k = 1; k <= n; k++)
    {
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                map[i][j] = map[i][j] || (map[k][j] && map[i][k]);
            }
        }
    }
}

bool bellman_ford(int s)
{
    for (int i = 1; i <= n; i++)
    {
        dist[i]= -INF;
    }
    dist[s] = 100;
    for (int i = 1; i < n; i++)     // n-1次
    {
        for (int j = 0; j < m; j++)
        {
            int x = Edge[j].x;
            int y = Edge[j].y;
            if (dist[y] < dist[x] + g[y] && dist[x] + g[y] > 0)
            {
                dist[y] = dist[x] + g[y];
            }
        }
    }
    for (int j = 0; j < m; j++)
    {
        int x = Edge[j].x;
        int y = Edge[j].y;
        if (dist[y] < dist[x] + g[y] && dist[x] + g[y] > 0 && map[y][n])
        {
            return 1;
        }
    }
    return dist[n] > 0;
}

int main()
{
    int num, ed;
    while (scanf("%d", &n) != EOF)
    {
        if (n == -1)
        {
            break;
        }
        m = 0;
        memset(map, 0, sizeof(map));

        for (int st = 1; st <= n; st++)
        {
            scanf("%d%d", &g[st], &num);
            while (num--)
            {
                scanf("%d", &ed);
                map[st][ed] = 1;
                Edge[m].x = st;
                Edge[m].y = ed;
                m++;
            }
        }

        // 判断是否连通
        floyd();

        if (!map[1][n])
        {
            printf("hopeless\n");
            continue;
        }
        if (bellman_ford(1))
        {
            printf("winnable\n");
        }
        else
        {
            printf("hopeless\n");
        }
    }

    return 0;
}

参考

《最短路》