UVa 12551 - Shares

Problem

現在要購買股票,每一個股票都有其花費和預期的在未來的出售價格。

但是股票採用組合包的方式進行販售,但是每一種組合包都只能購買一次,請問在資金只有 C 元的情況下,最多能在未來淨利多少。

Sample Input

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
500
4 6
10 15
8 6
20 15
12 12
3 1 6 2 7 3 8
3 3 8 1 10 2 4
3 4 10 2 5 1 10
2 1 4 2 4
1 3 2
2 4 3 2 1
200000000
5 30
2800 3500
1400 4800
2900 2800
500 3800
3300 4700
2 2 13 4 15
4 4 1 1 22 3 17 5 22
1 3 2
1 3 6
4 1 11 2 5 3 7 5 15
1 5 1
4 2 26 1 21 3 8 5 26
2 3 5 2 26
4 2 30 4 12 3 7 5 14
3 3 8 2 20 5 3
1 5 30
2 1 29 3 3
5 3 3 1 20 5 26 4 9 2 25
3 1 2 2 16 3 5
2 5 5 4 26
5 2 18 5 10 4 18 1 12 3 30
3 2 5 3 27 5 4
4 3 2 4 8 1 20 2 6
3 2 14 1 1 4 22
5 2 23 3 26 1 27 5 3 4 6
1 2 16
4 1 13 4 10 2 23 5 2
1 1 14
1 2 20
1 3 14
2 3 21 1 22
1 2 27
3 5 24 1 26 3 13
5 4 15 3 3 2 21 1 5 5 16
4 2 22 5 1 4 10 1 30

Sample Output

1
2
52
2168800

Solution

每個東西只能購買一次,可見是一個 01 背包問題,但是由於 C 很大,也就是背包容量過大,導致 DP 上的困難。

但是題目並沒有特別說明測資的特殊性,後來才得知可以用 gcd 最大共同因數去降,就是縮小幣值,相當於換外國幣去思考。這麼一來 C 可以降很多,但在一般的背包問題中,gcd 的效應並不高。

把我的純真還回來啊,不想自己 yy 測資特殊性。

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 <stdio.h>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int C, n, m;
int x, s, q;
int cost[512], profit[512];
int cases = 0;
while (scanf("%d", &C) == 1) {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d %d", &cost[i], &profit[i]), profit[i] -= cost[i];
vector< pair<int, int> > items;
for (int i = 0; i < m; i++) {
scanf("%d", &x);
int c = 0, p = 0;
for (int j = 0; j < x; j++) {
scanf("%d %d", &s, &q);
c += cost[s] * q;
p += profit[s] * q;
}
if (c <= C && p > 0)
items.push_back(make_pair(c, p));
}
if (cases++) puts("");
if (items.size() == 0) {
puts("0");
continue;
}
if (items.size() == 1) {
printf("%d\n", items[0].second);
continue;
}
int g = C;
for (int i = 0; i < items.size(); i++)
g = __gcd(g, items[i].first);
C /= g;
for (int i = 0; i < items.size(); i++)
items[i].first /= g;
vector<int> dp(C + 1, 0);
for (int i = 0; i < items.size(); i++) {
for (int j = C; j >= items[i].first; j--)
dp[j] = max(dp[j], dp[j - items[i].first] + items[i].second);
}
printf("%d\n", dp[C]);
}
return 0;
}
/*
500
4 6
10 15
8 6
20 15
12 12
3 1 6 2 7 3 8
3 3 8 1 10 2 4
3 4 10 2 5 1 10
2 1 4 2 4
1 3 2
2 4 3 2 1
200000000
5 30
2800 3500
1400 4800
2900 2800
500 3800
3300 4700
2 2 13 4 15
4 4 1 1 22 3 17 5 22
1 3 2
1 3 6
4 1 11 2 5 3 7 5 15
1 5 1
4 2 26 1 21 3 8 5 26
2 3 5 2 26
4 2 30 4 12 3 7 5 14
3 3 8 2 20 5 3
1 5 30
2 1 29 3 3
5 3 3 1 20 5 26 4 9 2 25
3 1 2 2 16 3 5
2 5 5 4 26
5 2 18 5 10 4 18 1 12 3 30
3 2 5 3 27 5 4
4 3 2 4 8 1 20 2 6
3 2 14 1 1 4 22
5 2 23 3 26 1 27 5 3 4 6
1 2 16
4 1 13 4 10 2 23 5 2
1 1 14
1 2 20
1 3 14
2 3 21 1 22
1 2 27
3 5 24 1 26 3 13
5 4 15 3 3 2 21 1 5 5 16
4 2 22 5 1 4 10 1 30
*/
Read More +

UVa 12550 - How do spiders walk on water

Problem

一個可以行走在靜止水面上的蜘蛛,現在要靠近瀑布,瀑布會於鄰近周圍會產生流速。

蜘蛛最多可以在 P 速度的水面上前進,請問最近可以靠近瀑布多少。現在已知從靜止水面靠近瀑布的部分流速,在未知的部分根據觀察是前面單位距離 1 距離 2 的線性關係。$v_{i} = a v_{i-1} + b v_{i-2}$)

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
3 3 0 1 1 1
10 2 0 1 1 2
10 3 0 1 1 2
10 4 0 1 1 2
10 5 0 1 1 2
10 6 0 1 1 2
10 7 0 1 1 2
10 8 0 1 1 2
10 9 0 1 1 2
10 3 1 1 2 2 2 3 3 3 3 4 4
10 5 1 1 2 2 2 3 3 3 3 4 4
10 5 6 6 6 6 8 8 8 11 30 41 42
10 2 0 1 1 1 1 1 1 1 1 1 1
50 200 0 3 6 15 36

Sample Output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
The spider may fall!
7
6
6
5
5
5
4
4
2
The spider may fall!
The spider is going to fall!
The spider may fall!
45

Solution

其實這題不難,在最後已知得部分解二元一次方程式即可,把未知的流速算出來,統計可以跑多遠即可。

一開始看不懂題目,以為所有流速都是線性關係,求出來的答案怪怪的。從最後已知的四個流速推測剩餘流速。

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
#include <stdio.h>
#include <algorithm>
#include <sstream>
#include <iostream>
using namespace std;
char line[1048576];
pair<double, double> solve(double a1, double b1, double c1, double a2, double b2, double c2) {
// a1 x + b1 y = c1, a2 x + b2 y = c2
double dx, dy, d;
d = a1 * b2 - b1 * a2;
dx = c1 * b2 - b1 * c2;
dy = a1 * c2 - a2 * c1;
return make_pair(dx / d, dy / d);
}
int main() {
int D, P;
while (gets(line)) {
stringstream sin(line);
sin >> D >> P;
double d[32767];
int n = 0;
while (sin >> d[n]) n++;
int pos = 0;
if (n < D + 1) {
pair<double, double> sol = solve(d[n-4], d[n-3], d[n-2], d[n-3], d[n-2], d[n-1]);
// printf("%lf %lf\n", sol.first, sol.second);
for (int i = n; i < D + 1; i++, n++) {
d[i] = sol.first * d[i-2] + sol.second * d[i-1];
if (P < d[i]) break;
}
}
for (int i = 0; i < D + 1; i++) {
if (P < d[i]) break;
pos++;
}
if (pos == D + 1)
puts("The spider may fall!");
else if (pos == 0)
puts("The spider is going to fall!");
else
printf("%d\n", D - pos + 1);
}
return 0;
}
/*
*/
Read More +

UVa 12094 - Battle of the Triangle

Problem

平面上有士兵和戰車,分別有 S 個、T 個,接著會有 Q 組詢問,每組詢問有三條線,每組詢問之間的線保證斜率會彼此相同 (只是移動線,這需求非常奇怪。),請問三條線拉出的 7 個區域中,中間與外側三塊地士兵、戰車個數差異為何?

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
8 5 2
-1 8
-7 3
-2 1
-2 -1
-5 -2
6 -1
2 -4
-4 -5
1 7
1 1
3 4
-6 5
-12 -6
2 -2 10
-2 6 6
-5 -3 1
1 -1 5
1 -3 -3
5 3 -15
0 0 0

Sample Output

1
2
3
Battle Field 1:
Query 1: 1 -2
Query 2: 1 -1

Solution

先獲得需要劃分的斜率,對三種斜率進行點的排序,因此對得到六個排序結果 (士兵和戰車)。之後就能在排序結果中,二分搜尋該線的左側、右側分別有多少點。

解決這個之後,要來看看噁心的排容原理,這裡還是建議參照 flere 的圖示:

對於拉出的三角形三個交點編號 A, B, C,接著對其做區域編號,

(1) BC 線段的左邊 有區域 1 2 3 6
(2) AC 線段的左邊 有區域 2 6 7
(3) AB 線段的下面 有區域 2 3 4
(1) - (2) - (3) 就可以得到區域 1 - 2 - 7 - 4
就是我們要的答案

flere

在程式邏輯上,挑一點與其一線同側,另兩條線與點異側。

沒有辦法單獨對區域內部搜尋點個數,然後統計完再相減,即使使用 range query,也無法在有效時間內完成任意三角形的範圍搜索 (矩形可以考慮,用等腰直角三角形也好。)。

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include <stdio.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
#define eps 1e-6
const double pi = acos(-1);
struct Pt {
double x, y;
Pt(double a = 0, double b = 0):
x(a), y(b) {}
bool operator<(const Pt &a) const {
if(fabs(x-a.x) > eps)
return x < a.x;
return y < a.y;
}
Pt operator+(const Pt &a) const {
return Pt(x + a.x, y + a.y);
}
Pt operator-(const Pt &a) const {
return Pt(x - a.x, y - a.y);
}
Pt operator*(const double &a) const {
return Pt(x * a, y * a);
}
};
double dist(Pt a, Pt b) {
return hypot(a.x - b.x, a.y - b.y);
}
double length(Pt a) {
return hypot(a.x, a.y);
}
double dot(Pt a, Pt b) {
return a.x * b.x + a.y * b.y;
}
double cross2(Pt a, Pt b) {
return a.x * b.y - a.y * b.x;
}
double cross(Pt o, Pt a, Pt b) {
return (a.x-o.x)*(b.y-o.y) - (a.y-o.y)*(b.x-o.x);
}
double angle(Pt a, Pt b) {
return acos(dot(a, b) / length(a) / length(b));
}
Pt rotateRadian(Pt a, double radian) {
double x, y;
x = a.x * cos(radian) - a.y * sin(radian);
y = a.x * sin(radian) + a.y * cos(radian);
return Pt(x, y);
}
Pt getIntersection(Pt p, Pt l1, Pt q, Pt l2) {
double a1, a2, b1, b2, c1, c2;
double dx, dy, d;
a1 = l1.y, b1 = -l1.x, c1 = a1 * p.x + b1 * p.y;
a2 = l2.y, b2 = -l2.x, c2 = a2 * q.x + b2 * q.y;
d = a1 * b2 - a2 * b1;
dx = b2 * c1 - b1 * c2;
dy = a1 * c2 - a2 * c1;
return Pt(dx / d, dy / d);
}
struct Line {
int A, B, C;
bool operator<(const Line &a) const {
double t1 = atan2(B, A);
double t2 = atan2(a.B, a.A);
if (t1 < 0) t1 += pi;
if (t2 < 0) t2 += pi;
return t1 < t2;
}
};
Pt getIntersection(Line l1, Line l2) {
double a1, a2, b1, b2, c1, c2;
double dx, dy, d;
a1 = l1.A, b1 = l1.B, c1 = -l1.C;
a2 = l2.A, b2 = l2.B, c2 = -l2.C;
d = a1 * b2 - a2 * b1;
dx = b2 * c1 - b1 * c2;
dy = a1 * c2 - a2 * c1;
return Pt(dx / d, dy / d);
}
struct cmp {
static Line base;
bool operator() (const Pt &p1, const Pt &p2) const {
double c1, c2;
c1 = p1.x * base.A + p1.y * base.B;
c2 = p2.x * base.A + p2.y * base.B;
if (fabs(c1 - c2) > eps)
return c1 < c2;
return false;
}
};
Line cmp::base;
int main() {
int cases = 0;
int n, m, q;
double x, y;
while (scanf("%d %d %d", &n, &m, &q) == 3 && n) {
vector<Pt> soldiers, tanks;
vector<Pt> soldier[3], tank[3];
Line Q[10000][3];
for (int i = 0; i < n; i++) {
scanf("%lf %lf", &x, &y);
soldiers.push_back(Pt(x, y));
}
for (int i = 0; i < m; i++) {
scanf("%lf %lf", &x, &y);
tanks.push_back(Pt(x, y));
}
for (int i = 0; i < q; i++) {
for (int j = 0; j < 3; j++) {
scanf("%d %d %d", &Q[i][j].A, &Q[i][j].B, &Q[i][j].C);
if (Q[i][j].A < 0 || (Q[i][j].A == 0 && Q[i][j].B < 0)) {
Q[i][j].A = -Q[i][j].A;
Q[i][j].B = -Q[i][j].B;
Q[i][j].C = -Q[i][j].C;
}
}
sort(Q[i], Q[i] + 3);
}
for (int i = 0; i < 3; i++) {
soldier[i] = soldiers;
tank[i] = tanks;
cmp::base = Q[0][i];
sort(soldier[i].begin(), soldier[i].end(), cmp());
sort(tank[i].begin(), tank[i].end(), cmp());
}
// for (int i = 0; i < 3; i++) {
// for (int j = 0; j < soldier[i].size(); j++)
// printf("%.2lf %.2lf ,", soldier[i][j].x, soldier[i][j].y);
// puts("\n--++--");
// }
printf("Battle Field %d:\n", ++cases);
for (int i = 0; i < q; i++) {
// for (int j = 0; j < 3; j++)
// printf("%d %d %d -\n", Q[i][j].A, Q[i][j].B, Q[i][j].C);
Pt pabc[3];
pabc[0] = getIntersection(Q[i][1], Q[i][2]); // bc
pabc[1] = getIntersection(Q[i][0], Q[i][2]); // ac
pabc[2] = getIntersection(Q[i][0], Q[i][1]); // ab
int ret1 = 0, ret2 = 0;
int tmp[3];
for (int j = 0; j < 3; j++) {
cmp::base = Q[i][j];
tmp[j] = (int)(lower_bound(soldier[j].begin(), soldier[j].end(),
pabc[(j+1)%3], cmp()) - soldier[j].begin());
int v1 = (Q[i][j].A * pabc[j].x + Q[i][j].B * pabc[j].y + Q[i][j].C < 0);
int v2 = (Q[i][j].A * soldier[j][0].x + Q[i][j].B * soldier[j][0].y + Q[i][j].C < 0);
int v3 = (Q[i][j].A * soldier[j][soldier[j].size()-1].x + Q[i][j].B * soldier[j][soldier[j].size()-1].y + Q[i][j].C < 0);
if (j == 0) {
if (tmp[j]) {
if (v1 != v2)
tmp[j] = soldier[j].size() - tmp[j];
} else {
if (v1 == v3)
tmp[j] = soldier[j].size() - tmp[j];
}
} else {
if (tmp[j]) {
if (v1 == v2)
tmp[j] = soldier[j].size() - tmp[j];
} else {
if (v1 != v3)
tmp[j] = soldier[j].size() - tmp[j];
}
}
// printf("[%d] soldier %d\n", j, tmp[j]);
}
ret1 = tmp[0] - tmp[1] - tmp[2];
for (int j = 0; j < 3; j++) {
cmp::base = Q[i][j];
tmp[j] = (int)(lower_bound(tank[j].begin(), tank[j].end(),
pabc[(j+1)%3], cmp()) - tank[j].begin());
int v1 = (Q[i][j].A * pabc[j].x + Q[i][j].B * pabc[j].y + Q[i][j].C < 0);
int v2 = (Q[i][j].A * tank[j][0].x + Q[i][j].B * tank[j][0].y + Q[i][j].C < 0);
int v3 = (Q[i][j].A * tank[j][tank[j].size()-1].x + Q[i][j].B * tank[j][tank[j].size()-1].y + Q[i][j].C < 0);
if (j == 0) {
if (tmp[j]) {
if (v1 != v2)
tmp[j] = tank[j].size() - tmp[j];
} else {
if (v1 == v3)
tmp[j] = tank[j].size() - tmp[j];
}
} else {
if (tmp[j]) {
if (v1 == v2)
tmp[j] = tank[j].size() - tmp[j];
} else {
if (v1 != v3)
tmp[j] = tank[j].size() - tmp[j];
}
}
// printf("[%d] tank %d\n", j, tmp[j]);
}
ret2 = tmp[0] - tmp[1] - tmp[2];
printf("Query %d: %d %d\n", i+1, ret1, ret2);
}
}
return 0;
}
/*
8 5 2
-1 8
-7 3
-2 1
-2 -1
-5 -2
6 -1
2 -4
-4 -5
1 7
1 1
3 4
-6 5
-12 -6
2 -2 10
-2 6 6
-5 -3 1
1 -1 5
1 -3 -3
5 3 -15
0 0 0
*/
Read More +

UVa 11600 - Masud Rana

Problem

給 N 個城市,城市之間會有 M 條當前的安全邊,在其餘邊皆有邪惡組織出現,來阻擋城市之間的運行。

現在人在編號 1,每次將隨機挑任何相鄰的城市走過去 (隔天又會再挑一個鄰近的城市),如果走過去的路上遇到邪惡組織則會將其殲滅,請問期望值需要幾天才能將 N 個城市彼此之間都存有連通路徑。

Sample Input

1
2
3
4
5
2
3 1
2 3
4 1
2 3

Sample Output

1
2
Case 1: 1.000000
Case 2: 3.500000

Solution

特別小心輸出的誤差要在 1e-6,以為只需要輸出 1 位,結果一直 WA。

事實上,將狀態壓縮成每一個連通元件的節點個數,對於連通元件之間做拉邊即可。

對於狀態 u, v,期望值 E[u] = 1 + E[v] p + E[u] q,

E[v] * p 表示:將兩個不同連通元件之間拉邊,則會將兩個連通元件融合,機率 p。
E[u] * q 表示:在各自的連通元件內布拉邊,不影響狀態結果。

左移一下得到 E[u] = (1 + E[v] * p) / (1 - q);

這一題必須考慮現在位於哪個連通元件,所以特別標記狀態的第一個連通元件為當前所在位置。

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
103
104
#include <stdio.h>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
// similar 1390 - Interconnect
int parent[32], weight[32];
int findp(int x) {
return parent[x] == x ? x : findp(parent[x]);
}
void joint(int x, int y) {
x = findp(x), y = findp(y);
if (x == y) return;
if (weight[x] > weight[y])
parent[y] = x, weight[x] += weight[y];
else
parent[x] = y, weight[y] += weight[x];
}
#define hash_mod 1000003
struct state {
vector<int> c;
unsigned int hash() {
unsigned int a = 63689, b = 378551;
unsigned int value = 0;
for (int i = 0; i < c.size(); i++) {
value = value * a + c[i];
a *= b;
}
return value % hash_mod;
}
bool operator<(const state &a) const {
if (c.size() != a.c.size())
return c.size() < a.c.size();
for (int i = 0; i < c.size(); i++)
if (c[i] != a.c[i])
return c[i] < a.c[i];
return false;
}
};
map<state, double> hash[hash_mod];
double dfs(state &u) {
if (u.c.size() == 1) return 0;
sort(u.c.begin() + 1, u.c.end());
int h = u.hash();
if (hash[h].find(u) != hash[h].end())
return hash[h][u];
double &ret = hash[h][u];
double self = 0, total = 0;
ret = 0;
for (int i = 0; i < u.c.size(); i++)
total += u.c[i];
total = total - 1, self = u.c[0] - 1;
for (int i = 1; i < u.c.size(); i++) {
state v = u;
v.c[0] += v.c[i];
v.c.erase(v.c.begin() + i);
ret += u.c[i] * dfs(v);
}
// E[u] = 1 + E[v] * p + E[u] * q
ret = (ret / total) + 1;
ret = ret / (1 - self / total);
return ret;
}
int main() {
int n, m, x, y;
int testcase, cases = 0;
scanf("%d", &testcase);
while (testcase--) {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
parent[i] = i, weight[i] = 1;
for (int i = 0; i < m; i++) {
scanf("%d %d", &x, &y);
joint(x, y);
}
state st;
for (int i = 1; i <= n; i++) {
if (parent[i] == i && parent[i] == findp(1))
st.c.push_back(weight[i]);
}
for (int i = 1; i <= n; i++) {
if (parent[i] == i && parent[i] != findp(1)) // root
st.c.push_back(weight[i]);
}
printf("Case %d: %lf\n", ++cases, dfs(st));
}
return 0;
}
/*
2
3 1
2 3
4 1
2 3
9999
3 3
1 2
2 3
3 1
*/
Read More +

UVa 11529 - Strange Tax Calculation

Problem

任挑三個點拉出三角形,三角形內部的點數期望值為何?

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
5
29 84
81 81
28 36
60 40
85 38
5
0 0
10 0
0 10
10 10
6 7
0

Sample Output

1
2
City 1: 0.20
City 2: 0.20

Solution

反過來寫,這一點會被多少個三角形包含住。

為了要計算這一個點 P 被多少三角形包含住,把這個點 P 當作基礎點,對其他點做極角排序。排序完套用極角掃描線算法,對於當前線上的點 Q,往回追溯 180 度內,任挑兩個點與其並成三角形,保證不包含 P。

那麼要得到包含 P 的就反過來用全部組合扣到不包含的結果。

因為要窮舉每一點做極角排序,作法會在 O(n^2 log n)

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
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define eps 1e-9
const double pi = acos(-1);
struct Pt {
double x, y;
double angle;
Pt(double a = 0, double b = 0):x(a), y(b) {
angle = atan2(b, a);
}
bool operator<(const Pt &a) const {
if (fabs(angle - a.angle) > eps)
return angle < a.angle;
return false;
}
};
long long C[1300][1300] = {};
long long getContainTriangle(int st, Pt D[], int n) {
static Pt A[4096];
int m = 0;
for (int i = 0; i < n; i++) {
if (i == st) continue;
A[m++] = Pt(D[i].x - D[st].x, D[i].y - D[st].y);
}
sort(A, A + m);
for (int i = 0; i < m; i++)
A[i + m] = A[i], A[i+m].angle += 2 * pi;
long long ret = 0;
for (int i = 0, j = 1; i < m; i++) { // point(i, ?, ?)
while (A[j].angle - A[i].angle <= pi - eps) j++;
ret += C[j - i - 1][2];
}
return C[m][3] - ret;
}
int main() {
C[0][0] = 1;
for (int i = 0; i < 1205; i++) {
C[i][0] = 1;
for (int j = 1; j <= i; j++)
C[i][j] = C[i-1][j-1] + C[i-1][j];
}
int n, cases = 0;
Pt D[1500];
while (scanf("%d", &n) == 1 && n) {
for (int i = 0; i < n; i++)
scanf("%lf %lf", &D[i].x, &D[i].y);
long long contain = 0;// contain
for (int i = 0; i < n; i++)
contain += getContainTriangle(i, D, n); // with i-th point.
printf("City %d: %.2lf\n", ++cases, (double)contain / C[n][3]);
}
return 0;
}
/*
5
29 84
81 81
28 36
60 40
85 38
5
0 0
10 0
0 10
10 10
6 7
0
*/
Read More +

UVa 1331 - Minimax Triangulation

Problem

將一個簡單多邊形三角化,並且讓最大面積的三角形越小越好。

Sample Input

1
2
3
4
5
6
7
8
1
6
7 0
6 2
9 5
3 5
0 3
1 1

Sample Output

1
9.0

Solution

矩陣鏈乘積的方式著手 dp。

在此必須檢查劃分兩區間的三角形中內部不包含任何點,這裡利用外積 cross 進行計算。

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
#define eps 1e-6
struct Pt {
double x, y;
Pt(double a = 0, double b = 0):
x(a), y(b) {}
bool operator<(const Pt &a) const {
if (fabs(x-a.x) > eps)
return x < a.x;
if (fabs(y-a.y) > eps)
return y < a.y;
return false;
}
Pt operator-(const Pt &a) const {
return Pt(x - a.x, y - a.y);
}
Pt operator+(const Pt &a) const {
return Pt(x + a.x, y + a.y);
}
bool operator==(const Pt &a) const {
return (fabs(x - a.x) < eps && fabs(y - a.y) < eps);
}
void read() {
scanf("%lf %lf", &x, &y);
}
};
struct Seg {
Pt s, e;
Seg(Pt a = Pt(), Pt b = Pt()):
s(a), e(b) {}
};
double dist(Pt a, Pt b) {
return hypot(a.x - b.x, a.y - b.y);
}
double dot(Pt a, Pt b) {
return a.x * b.x + a.y * b.y;
}
double cross2(Pt a, Pt b) {
return a.x * b.y - a.y * b.x;
}
double cross(Pt o, Pt a, Pt b) {
return (a.x-o.x)*(b.y-o.y)-(a.y-o.y)*(b.x-o.x);
}
int between(Pt a, Pt b, Pt c) {
return dot(c - a, b - a) >= 0 && dot(c - b, a - b) >= 0;
}
int onSeg(Pt a, Pt b, Pt c) {
return between(a, b, c) && fabs(cross(a, b, c)) < eps;
}
int intersection(Pt as, Pt at, Pt bs, Pt bt) {
if(cross(as, at, bs) * cross(as, at, bt) < 0 &&
cross(at, as, bs) * cross(at, as, bt) < 0 &&
cross(bs, bt, as) * cross(bs, bt, at) < 0 &&
cross(bt, bs, as) * cross(bt, bs, at) < 0)
return 1;
return 0;
}
double distProjection(Pt as, Pt at, Pt s) {
int a, b, c;
a = at.y - as.y;
b = as.x - at.x;
c = - (a * as.x + b * as.y);
return fabs(a * s.x + b * s.y + c) / hypot(a, b);
}
double ptToSeg(Seg seg, Pt p) {
double c = 1e+30;
if(between(seg.s, seg.e, p))
c = min(c, distProjection(seg.s, seg.e, p));
else
c = min(c, min(dist(seg.s, p), dist(seg.e, p)));
return c;
}
double getArea(Pt a, Pt b, Pt c) {
return fabs(cross(a, b, c))/2.0;
}
int isEmptyTriangle(Pt a, Pt b, Pt c, Pt D[], int n) {
for (int i = 0; i < n; i++) {
if (D[i] == a || D[i] == b || D[i] == c)
continue;
if (cross(a, D[i], b) * cross(a, D[i], c) < 0 &&
cross(b, D[i], a) * cross(b, D[i], c) < 0 &&
cross(c, D[i], a) * cross(c, D[i], b) < 0)
return 0;
}
return 1;
}
int main() {
int testcase, n;
Pt D[128];
scanf("%d", &testcase);
while (testcase--) {
scanf("%d", &n);
for (int i = 0; i < n; i++)
D[i].read();
for (int i = 0; i < n; i++)
D[i + n] = D[i];
double dp[128][128];
for (int i = 0; i < 2 * n; i++) {
for (int j = 0; j < 2 * n; j++) {
dp[i][j] = 1e+30;
}
dp[i][i] = dp[i][i+1] = 0;
}
double ret = 1e+30;
for (int i = 2; i < n; i++) {
for (int j = 0; j < n; j++) {// [j, j+i]
int l = j, r = j + i;
double &v = dp[l][r];
for (int k = l+1; k < r; k++) {
if (isEmptyTriangle(D[l], D[r], D[k], D, n))
v = min(v, max(max(dp[l][k], dp[k][r]), getArea(D[l], D[r], D[k])));
}
}
}
for (int i = 0; i < n; i++)
ret = min(ret, dp[i][i + n - 1]);
printf("%.1lf\n", ret);
}
return 0;
}
/*
1
6
7 0
6 2
9 5
3 5
0 3
1 1
*/
Read More +

UVa 12058 - Highway Monitor

Problem

在 n 個點的高速公路上,需要監視 m 條邊上的情況,監視器只能位於點上,並且可以監控所有與該點相連的邊,費用有限最多只能放置 k 個監視器,找到其中一種使用少於等於 k 個監視器的方法。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
5 7 2
1 2
1 3
1 5
2 4
2 5
3 5
4 5
5 7 3
1 2
1 3
1 5
2 4
2 5
3 5
4 5

Sample Output

1
2
Case #1: no
Case #2: yes 1 2 5

Solution

解決最少點集覆蓋所有邊,是一個 NP 問題,雖然這一題已經給定限制搜索必須小於等於 K。

對於 DLX (Dancing Links and Algorithm X) 運用在最少重複覆蓋而言,K 是沒有太大的必要,事實上根據 degree 最大的節點開始窮舉的效果跟 DLX 差不多的。而這一題沒有要求最少,只是請求在範圍內的任一解輸出即可。

DLX 一開始用在精準覆蓋,解決重複覆蓋的效果只能說還算可以,大多的時間都花在計算估價函數,那個啟發式估價是用最簡單的貪心。有時候需要覆蓋的 colume 數量非常多,所以寫法上用 memset 也許是不錯的,但是用懶標記是更為快速。

DLX 的精神在於雙十字鏈表,並且每次找最少可能的 colume 開始窮舉,窮舉時會斷開所有相關在其他 colume 的可能,並在移除掉不需要窮舉的 colume,而在重複覆蓋上則不會移除掉需要窮舉的 colume。

  • 精确覆盖:
    首先选择当前要覆盖的列(含1最少的列),将该列和能够覆盖到该列的行全部去掉,再枚举添加的方法。枚举某一行r,假设它是解集中的一个,那么该行所能覆盖到的所有列都不必再搜,所以删除该行覆盖到的所有列,又由于去掉的列相当于有解,所以能够覆盖到这些列的行也不用再搜,删之。
  • 重复覆盖:
    首先选择当前要覆盖的列(同上),将该列删除,枚举覆盖到该列的所有行:对于某一行r,假设它是解集中的一个,那么该行所能覆盖到的列都不必再搜,所以删除该行覆盖到的所有列。注意此时不用删去覆盖到这些列的行,因为一列中允许有多个1。这里有一个A*的优化:估价函数h意义为从当前状态最好情况下需要添加几条边才能覆盖。

這一題會有 n 個 row,每一個 row 會覆蓋第 i 個節點覆蓋哪些邊。因此需要對所有輸入的邊進行編號,也就是 colume 會有 m 個。m 最大 50 萬,窮舉起來相當刺激。

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <algorithm>
#include <assert.h>
using namespace std;
#define MAXV 0x3f3f3f3f
#define MAXE 1048576
#define MAXC 1048576
#define MAXR 1024
struct DacingLinks {
int left, right;
int up, down;
int ch, rh;
int data; // extra info
} DL[MAXE];
int s[MAXC], o[MAXR], head, size, Ans, findflag;
void Remove(int c) {
static int i;
for(i = DL[c].down; i != c; i = DL[i].down) {
DL[DL[i].right].left = DL[i].left;
DL[DL[i].left].right = DL[i].right;
s[DL[i].ch]--;
}
}
void Resume(int c) {
static int i;
for(i = DL[c].down; i != c; i = DL[i].down) {
DL[DL[i].right].left = i;
DL[DL[i].left].right = i;
s[DL[i].ch]++;
}
}
int used[MAXC] = {};
int H() {
static int c, ret, i, j, time = 0;
for(c = DL[head].right, ++time, ret = 0; c != head; c = DL[c].right) {
if(used[c] != time) {
ret ++, used[c] = time;
for(i = DL[c].down; i != c; i = DL[i].down)
for(j = DL[i].right; j != i; j = DL[j].right)
used[DL[j].ch] = time;
}
}
return ret;
}
void DFS(int k) {
if(k + H() >= Ans) return;
if(DL[head].right == head) {
if(k < Ans) {
Ans = k, findflag = 1;
printf("yes");
for (int i = 0; i < k; i++)
printf(" %d", DL[o[i]].data);
puts("");
}
return;
}
int t = MAXV, c, i, j;
for(i = DL[head].right; i != head; i = DL[i].right) {
if(s[i] < t) {
t = s[i], c = i;
}
}
for(i = DL[c].down; i != c; i = DL[i].down) {
o[k] = i;
Remove(i);
for(j = DL[i].right; j != i; j = DL[j].right) Remove(j);
DFS(k+1);
for(j = DL[i].left; j != i; j = DL[j].left) Resume(j);
Resume(i);
if (findflag) break;
}
}
int new_node(int up, int down, int left, int right) {
assert(size < MAXE);
DL[size].up = up, DL[size].down = down;
DL[size].left = left, DL[size].right = right;
DL[up].down = DL[down].up = DL[left].right = DL[right].left = size;
return size++;
}
void addrow(int n, int Row[], int data) {
int a, r, row = -1, k;
for(a = 0; a < n; a++) {
r = Row[a];
DL[size].ch = r, s[r]++;
DL[size].data = data;
if(row == -1) {
row = new_node(DL[DL[r].ch].up, DL[r].ch, size, size);
DL[row].rh = a;
}else {
k = new_node(DL[DL[r].ch].up, DL[r].ch, DL[row].left, row);
DL[k].rh = a;
}
}
}
void init(int m) {
size = 0;
head = new_node(0, 0, 0, 0);
int i;
for(i = 1; i <= m; i++) {
new_node(i, i, DL[head].left, head);
DL[i].ch = i, s[i] = 0;
}
}
int main() {
int testcase, cases = 0;
int n, m, k, x, y;
scanf("%d", &testcase);
while (testcase--) {
scanf("%d %d %d", &n, &m, &k);
vector<int> g[1024];
for (int i = 1; i <= m; i++) {
scanf("%d %d", &x, &y);
g[x].push_back(i);
g[y].push_back(i);
}
assert(m < MAXC);
init(m);
int row[1024];
for (int i = 1; i <= n; i++) {
sort(g[i].begin(), g[i].end());
for (int j = 0; j < g[i].size(); j++)
row[j] = g[i][j];
addrow(g[i].size(), row, i);
}
printf("Case #%d: ", ++cases);
Ans = k + 1, findflag = 0;
DFS(0);
if (Ans == k+1)
puts("no");
}
return 0;
}
Read More +

UVa 12052 - Cyber cafe

Problem

給一張圖有 N 個節點、M 條邊,其中要放置 S 台新主機於其中 S 個節點,而沒放置的節點繼續使用舊主機,為了服務舊主機的網咖,每個舊節點旁邊最多只能有一個新主機網咖。

請問有多少種放置方法。

Sample Input

1
2
3
4
5
6
7
8
9
10
Dhaka
6 2 7
AB BC CD DE EF FA AD
Chittagong
4 3 4
AB AC AD BC
Sylhet
3 2 3
AB BC CA
TheEnd

Sample Output

1
2
3
4
5
6
7
Dhaka
9
Chittagong
1
Sylhet
0
TheEnd

Solution

對於每一個節點的連接方式用一個 32-bit 壓縮,接著窮舉所有可能放置方法 state,對於沒有放置的節點,直接壓縮結果與 state 做 AND 運算,算 bits 數是否都小於 2。

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
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int main() {
char ss[1024];
int n, s, p;
while (scanf("%s", &ss) == 1) {
printf("%s\n", ss);
if (!strcmp(ss, "TheEnd"))
break;
scanf("%d %d %d", &n, &s, &p);
int g[26][26] = {};
for (int i = 0; i < p; i++) {
scanf("%s", ss);
int x = ss[0] - 'A', y = ss[1] - 'A';
g[x][y] = g[y][x] = 1;
}
int mask[26] = {};
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
mask[i] |= g[i][j]<<j;
int ret = 0;
for (int i = (1<<n)-1; i >= 0; i--) {
if (__builtin_popcount(i) == s) {
int ok = 1;
for (int j = 0; j < n && ok; j++) {
if ((i>>j)&1) continue;
if (__builtin_popcount(mask[j]&i) >= 2)
ok = 0;
}
ret += ok;
}
}
printf("%d\n", ret);
}
return 0;
}
Read More +

UVa 12051 - Mazes in Higher Dimensions

Problem

好比 2D 方格,從左下角到右上角的方法數。而這一題是在三維空間,一樣的方式要越來越靠近右上方的頂點,但是部分點會有障礙物,會造成無法通行。

題目給定的維度事實上是終點座標,而非該維度數,用 row major 的時候要計算 dim[i]+1

Sample Input

1
2
3
4
5
6
7
8
3 0
5 5 5
3 1
9 8 7
1 1 1
0 0

Sample Output

1
2
Case 1: 756756
Case 2: 6318655200

Solution

特地用懶標記完成 dp 計算,但是忘了有可能無法抵達終點,忘了補上最對於終點的懶標記操作,直接輸出 dp[ret] 結果一直噴 WA。

懶標記檢查 if (used[ret] != testcase) dp[ret] = 0;

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
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
#define MAXN 3000005
long long dp[MAXN] = {};
int used[MAXN] = {}, ob[MAXN] = {}; // obstacle
int main() {
memset(dp, 0, sizeof(dp));
memset(ob, 0, sizeof(ob));
memset(used, 0, sizeof(used));
int n, m, dim[16], row[16], v[16];
int testcase = 0, cases = 0;
while (scanf("%d %d", &n, &m) == 2 && n+m) {
for (int i = 0; i < n; i++) {
scanf("%d", &dim[i]);
dim[i]++;
}
testcase++;
row[n - 1] = 1;
for (int i = n - 2; i >= 0; i--)
row[i] = row[i+1] * dim[i+1];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
scanf("%d", &v[j]);
int x = 0;
for (int j = 0; j < n; j++)
x += v[j] * row[j];
ob[x] = testcase;
}
if(ob[0] == testcase){
printf("Case %d: 0\n", ++cases);
continue;
}
int ret = 0;
for (int i = 0; i < n; i++)
ret += (dim[i] - 1) * row[i];
queue<int> Q;
Q.push(0), used[0] = testcase;
dp[0] = 1;
while (!Q.empty()) {
int x = Q.front();
Q.pop();
long long ways = dp[x];
for (int i = 0; i < n; i++)
v[i] = x / row[i], x %= row[i];
for (int i = 0; i < n; i++) {
v[i]++;
if (v[i] < dim[i]) {
x = 0;
for (int j = 0; j < n; j++)
x += v[j] * row[j];
if (ob[x] != testcase) {
if (used[x] != testcase)
dp[x] = 0;
dp[x] += ways;
if (used[x] != testcase)
Q.push(x), used[x] = testcase;
}
}
v[i]--;
}
}
if (used[ret] != testcase) dp[ret] = 0;
printf("Case %d: %lld\n", ++cases, dp[ret]);
}
return 0;
}
/*
3 0
5 5 5
3 1
9 8 7
1 1 1
3 2
9 8 7
1 1 1
5 6 6
3 2
9 8 7
2 3 4
9 8 7
3 2
9 8 7
2 3 4
9 8 7
0 0
*/
Read More +

UVa 10381 - The Rock

Problem

給定一個 N x M 地圖,已知有部分的牆壁和一個透明的牆壁,每一個障礙物都佔據一個方格,而透明牆壁一開始不知道位於何處,直到碰壁的時候才發現,找一條最慘情況下的最短路徑。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
8 8
..X.....
........
##.##...
........
##.##...
##.##...
........
..E.....
3 4
..X.
.##.
.E..

Sample Output

1
2
15
11

Solution

最小化最大值,首先窮舉任何一個透明牆壁可能出現的地方,對於透明牆壁的鄰近四格建立再碰壁方向下,抵達終點的最短路徑。

接著,使用最短路的方式進行更新,在這裡使用 dijkstra 的方式,對於每一個點的狀態為 (走到這裡第幾步) = 從起點走到這,最慘的偏移路徑最小化 為何。

概念上理解,設計一條路徑,路徑畫好後,對於每一點賭下一個點就是透明牆壁,偏移路徑長最長為何就會是該路徑的花費。

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <stdio.h>
#include <string.h>
#include <queue>
#include <assert.h>
#include <algorithm>
using namespace std;
char g[64][64];
int dist[64][64], walldist[64][64][4];
int n, m;
const int dx[] = {0, 1, 0, -1};
const int dy[] = {1, 0, -1, 0};
struct State {
int x, y;
int g, h;
State(int a=0, int b=0, int c=0, int d=0):
x(a), y(b), g(c), h(d) {}
bool operator<(const State &a) const {
return h > a.h;
}
};
int dp[40][40][40 * 40];
int search(int sx, int sy, int ex, int ey) {
priority_queue<State> pQ;
State u, v;
int tx, ty, h;
pQ.push(State(sx, sy, 0, 0));
memset(dp, 63, sizeof(dp));
while (!pQ.empty()) {
u = pQ.top(), pQ.pop();
if (u.h > dp[u.x][u.y][u.g])
continue;
if (u.x == ex && u.y == ey)
return u.h;
for (int i = 0; i < 4; i++) {
tx = u.x + dx[i], ty = u.y + dy[i];
if (tx < 0 || ty < 0 || tx >= n || ty >= m)
continue;
if (g[tx][ty] == '#' || g[tx][ty] == 'E')
continue;
if (g[tx][ty] == '.')
h = max(u.h, u.g + walldist[u.x][u.y][i]);
else if (g[tx][ty] == 'X')
h = max(u.h, u.g);
assert(u.g + 1 < 40 * 40);
if (dp[tx][ty][u.g + 1] > h) {
dp[tx][ty][u.g + 1] = h;
pQ.push(State(tx, ty, u.g + 1, h));
}
}
}
return 0;
}
void bfs(int sx, int sy) {
memset(dist, 63, sizeof(dist));
queue<int> X, Y;
int tx, ty;
X.push(sx), Y.push(sy);
dist[sx][sy] = 0;
while (!X.empty()) {
sx = X.front(), X.pop();
sy = Y.front(), Y.pop();
for (int i = 0; i < 4; i++) {
tx = sx + dx[i], ty = sy + dy[i];
if (tx < 0 || ty < 0 || tx >= n || ty >= m)
continue;
if (g[tx][ty] == '#' || dist[tx][ty] <= dist[sx][sy] + 1)
continue;
dist[tx][ty] = dist[sx][sy] + 1;
X.push(tx), Y.push(ty);
}
}
}
int main() {
int testcase;
scanf("%d", &testcase);
while (testcase--) {
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++)
scanf("%s", g[i]);
int sx, sy, ex, ey, tx, ty;
memset(walldist, 0, sizeof(walldist));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (g[i][j] == 'E') sx = i, sy = j;
if (g[i][j] == 'X') ex = i, ey = j;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (g[i][j] != '.')
continue;
g[i][j] = '#';
bfs(ex, ey);
for (int k = 0; k < 4; k++) {
tx = i + dx[k], ty = j + dy[k];
if (tx < 0 || ty < 0 || tx >= n || ty >= m)
continue;
if (g[tx][ty] == '#')
continue;
walldist[tx][ty][(k+2)%4] = dist[tx][ty];
}
g[i][j] = '.';
}
}
int ret = search(sx, sy, ex, ey);
printf("%d\n", ret);
}
return 0;
}
/*
2
8 8
..X.....
........
##.##...
........
##.##...
##.##...
........
..E.....
3 4
..X.
.##.
.E..
*/
Read More +