#include <stdio.h> #define MAX 110 #define QMAX 1000 int energys[MAX][MAX]; int cost[MAX][MAX]; int doors; // 计算有向图的传递闭包 void allcosts(int n) { int i, j, k; for (k = 1; k <= n; k++) for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (cost[i][j] = cost[i][j] || cost[i][k] && cost[k][j]) ; } // 使用SPFA算法计算带有负权值的图的最短路径 void spfa(int x) { int i, door; int in_queue[MAX] = {0}, num[MAX] = {0}; int queue[QMAX] = {0}, front, rear; int d[MAX]; d[x] = 100; for (i = 2; i <= doors; i++) { d[i] = -100000; } front = rear = 0; rear = (rear+1)%QMAX; queue[rear] = x; in_queue[x] = 1; num[x]++; while (front != rear) { front = (front+1)%QMAX; door = queue[front]; in_queue[door] = 0; // 当某个结点的入队次数大于N,则存在负环(SPFA算法的最多松弛次数为N-1) if (num[door] <= doors) for (i = 1; i <= doors; i++) { if (energys[door][i] != -100000) { // 判断“d[door]+energys[door][i] > 0“是为了确保去到每个结点的权值都是大于0(以防到达N结点的路径出现负权值) if (d[i] < d[door]+energys[door][i] && d[door]+energys[door][i] > 0) { d[i] = d[door]+energys[door][i]; if (!in_queue[i]) { rear = (rear+1)%QMAX; queue[rear] = i; in_queue[i] = 1; num[i]++; } } } } else { // 这个负环有没有存在一条路径通向N结点 if (cost[door][doors]) d[doors] = 1; } // 当已经找到一条路径从1结点到N结点的权值大于0(可能不是最大路径),就可以判断为”winnable“ if (d[doors] > 0) { printf("winnable\n"); return; } } printf("hopeless\n"); return; } int main() { int i, j; int value, doorways; while (scanf("%d", &doors) && doors != -1) { for (i = 1; i <= doors; i++) { scanf("%d%d", &value, &doorways); // 初始化 energys数组 for (j = 1; j <= doors; j++) { energys[i][j] = -100000; cost[i][j] = 0; } energys[i][i] = 0; while (doorways--) { scanf("%d", &j); energys[i][j] = value; cost[i][j] = 1; } } allcosts(doors); // 如果结点1和结点N是连通的,使用SPFA算法 if (cost[1][doors]) spfa(1); else printf("hopeless\n"); } }