描述
题解
先使用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;
}