UVa 10557 - XYZZY

Contents

  1. 1. Problem
  2. 2. Solution
  3. 3. Code

Problem

題目網址

從起點開始走,判斷是否可以走到終點,節點會有不同能量加減,途中不得使能量變為 0。

Solution

(有正環可一直重複走使能量無限)
可以分成幾種情況,如果有正環:

  • 此段路可到終點 -> win
  • 此段路無法到終點

沒正環,但可以走到終點:

  • 途中不會使能量為負 -> win
  • 會使能量為負

所以先做一次 BFS 紀錄各點的連通狀況,再做 SPFA 找可行的路徑。

Code

UVa 10557UVa 10557 - XYZZY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include<cstdio>
#include<queue>
using namespace std;
#define N 101
#define M -10000000

struct Room
{
int door[N];
int w, n;
}room[N];

bool ok[N][N];//判斷兩點是否有連通
void BFS(int n);//求出任兩點是否有連通
bool SPFA(int n);
int main()
{
int n, i, j;
while (scanf("%d", &n) && n != -1)
{
for (i = 0; i <= n; i++)
for (j = 0; j <= n; j++)
ok[i][j] = false;

for (i = 1; i <= n; i++)
{
scanf("%d%d", &room[i].w, &room[i].n);
for (j = 0; j < room[i].n; j++)
scanf("%d", &room[i].door[j]);
}

for (i = 1; i <= n; i++)
BFS(i);

puts(SPFA(n) ? "winnable" : "hopeless");
}

return 0;
}
void BFS(int n)
{
queue<int> Q;
Q.push(n);

while (!Q.empty())
{
int idx = Q.front();
Q.pop();
if (ok[n][idx])
continue;
else
ok[n][idx] = true;

for (int i = 0; i < room[idx].n; i++)
Q.push(room[idx].door[i]);
}

}
bool SPFA(int n)
{
bool inQ[N] = {}, cycle = false;
int e[N] = {}, r[N] = {}, i;
for (i = 0; i <= n; i++)
e[i] = M;
e[1] = 100;

queue<int> Q;
Q.push(1);
while (!Q.empty())
{
int idx = Q.front();
Q.pop();

if (idx == n)
return true;
else if (r[idx] > n - 1)//產生正環
{
if (ok[idx][n])//如果可以從 idx 走到 n
return true;
else//不行的話就不用再判斷此點了
e[idx] = 10000000;
continue;
}


inQ[idx] = false;

for (i = 0; i < room[idx].n; i++)
{
int k = room[idx].door[i], energy = e[idx] + room[idx].w;
if (energy > e[k] && energy > 0)//不能為負
{
e[k] = energy;
r[k] = r[idx] + 1;//紀錄最短路徑的邊數
if (!inQ[k])
Q.push(k);
}
}
}

return e[n] > 0;
}