題目連結
位元DP。
我們定義 $dp[i][j] = k$, $j$ 為已經拾取過果實的地方,$i$ 為最後所停之處,$dp[i][j]$為拾取果實後停在$i$的總步數。
初始化的話,$dp[i][1<<i] = $ 從出發點到此的距離,其餘 $\infty$。
計算的話,假設我們有三個點,我們現在要求取$dp[0][3]$(已經在0, 1拿完果實,並停在0),那我們的其中一種可行走法為$dp[1][2] + dist[1][0]$,也就是說,從只去過1的狀態走到0來!所以更新的話,就是:
1
2
|
dp[i][j] = min(dp[i][j], dp[k][j - (1 << i)] + dist[i][k]);
|
AC Code
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
|
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
const int oo = 0x3f3f3f3f;
int main()
{
int n, m;
while (scanf("%d %d", &n, &m) == 2) {
int sx = -1, sy = -1;
vector<ii> loc;
for (int i = 0; i < n; i++) {
char str[m + 2];
scanf("%s", str);
for (int j = 0; j < m; j++) {
if (str[j] == 'L') {
sx = i;
sy = j;
} else if (str[j] == '.') {
} else {
loc.push_back(ii(i, j));
}
}
}
loc.push_back(ii(sx, sy));
int pts = loc.size();
// get dist
int dist[pts][pts];
for (int i = 0; i < pts; i++)
fill(dist[i], dist[i] + pts, oo);
for (int i = 0; i < pts; i++)
for (int j = 0; j < pts; j++)
dist[i][j] = max(abs(loc[i].first - loc[j].first),
abs(loc[i].second - loc[j].second));
// dp
// init
pts--; // #pts is the starting point
int dp[pts][(1 << pts)];
for (int i = 0; i < pts; i++) {
fill(dp[i], dp[i] + (1 << pts), oo);
dp[i][1 << i] = dist[i][pts];
}
for (int j = 0; j < (1 << pts); j++) {
for (int i = 0; i < pts; i++) {
for (int k = 0; k < pts; k++) {
if (((j >> k) & 1) == 1 && k != i) {
dp[i][j] = min(dp[i][j], dp[k][j - (1 << i)] + dist[i][k]);
}
}
}
}
int mx = oo;
for (int i = 0; i < pts; i++)
mx = min(mx, dp[i][(1 << pts) - 1] + dist[pts][i]);
printf("%d\n", mx == oo ? 0 : mx); // WA: might have no nuts
}
return 0;
}
|