POJ 3593 Sea Base Exploration, 状态压缩DP
地图中有K种物品,
1.空载情况下每走一步用能量1
2.取得物品i需要能量Ai
3.每取得一个物品, 每走一步的能量需要加Bi
4.*为起点,图中不能经过*,取得K种物品后返回*
问能否用不大于P的能量取得K种物品
PS: 条件4,在求得起点到所有点的最短路径后,要将*看作#,然后重新计算每对点对的最短路径.
状态f[s][i][j] , s为二进制状态,最后取得第i种物品中编号为j的物品的最短路径.
f[s][i][j] = min(f[s - (1 << k)][i0][j0] + d[i][j][i0][j0] * (1 + C[s - (1 << k)]) + A[k]),
其中(s >> k)&1 == 1, (s >> i0)&1 == 1, k != i0,
d[i][j][i0][j0]为第i种物品编号j到第i0种物品编号j0的距离,
C[s]记录状态s的每走一步需要的能量
1 #include <iostream>
2 #include <queue>
3 #include <algorithm>
4 using namespace std;
5
6 #define INF 0x33333333
7 #define min(a, b) ((a) < (b) ? (a) : (b))
8 char map[25][25];
9 bool g[25][25];
10 int id0[25][25], id1[25][25], id, A[10], B[10], C[1 << 10];
11 int f[1 << 10][10][10], d[10][10][10][10], dd[10][10], cnt[10];
12 int sta[1 << 10], one[1 << 10];
13 int T, M, N, K, P, sx, sy, ans;
14 int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
15
16 int calt(int x)
17 {
18 int i = 0;
19 while (x)
20 x &= (x - 1), i++;
21 return i;
22 }
23
24 int comp(int a, int b)
25 {
26 return one[a] < one[b];
27 }
28
29 void init()
30 {
31 for (int i = 0; i < (1 << K); i++)
32 {
33 sta[i] = i;
34 C[i] = 0;
35 for (int j = 0; j < K; j++)
36 if ((i >> j)&1)
37 C[i] += B[j];
38 }
39 sort(sta, sta + (1 << K), comp);
40 }
41
42 void bfs(int y, int x, int ddd[][10], int id)
43 {
44 bool vis[25][25] = {false};
45 int tx, ty, dis;
46 queue<int> Q;
47 Q.push(y), Q.push(x), Q.push(0);
48 vis[y][x] = true;
49 while (!Q.empty())
50 {
51 y = Q.front(), Q.pop();
52 x = Q.front(), Q.pop();
53 dis = Q.front(), Q.pop();
54 if (id0[y][x] != -1 && id0[y][x] != id)
55 ddd[id0[y][x]][id1[y][x]] = dis;
56 for (int i = 0; i < 4; i++)
57 {
58 tx = x + dir[i][0], ty = y + dir[i][1];
59 if (!vis[ty][tx] && g[ty][tx])
60 {
61 vis[ty][tx] = true;
62 Q.push(ty), Q.push(tx), Q.push(dis + 1);
63 }
64 }
65 }
66 }
67
68 int main()
69 {
70 for (int i = 0; i < (1 << 10); i++)
71 one[i] = calt(i);
72 //freopen("test.in", "r", stdin);
73 scanf("%d", &T);
74 while (T--)
75 {
76 memset(map, '#', sizeof (map));
77 memset(g, 0, sizeof (g));
78 memset(id0, -1, sizeof (id0));
79 memset(id1, -1, sizeof (id1));
80 memset(d, 0x33, sizeof (d));
81 memset(dd, 0x33, sizeof (dd));
82 memset(f, 0x33, sizeof (f));
83 memset(cnt, 0, sizeof (cnt));
84
85 scanf("%d %d %d %d", &M, &N, &K, &P);
86 for (int i = 1; i <= M; i++)
87 scanf("%s", map[i] + 1);
88 for (int i = 0; i < K; i++)
89 scanf("%d %d", &A[i], &B[i]);
90
91 init();
92 for (int i = 1; i <= M; i++)
93 for (int j = 1; j <= N; j++)
94 if (map[i][j] != '#')
95 {
96 g[i][j] = true;
97 if (map[i][j] == '*')
98 sy = i, sx = j;
99 else if (map[i][j] != '.')
100 {
101 id0[i][j] = map[i][j] - 'A';
102 id1[i][j] = cnt[map[i][j] - 'A']++;
103 }
104 }
105
106 bfs(sy, sx, dd, -1);
107 g[sy][sx] = false;
108 for (int i = 1; i <= M; i++)
109 for (int j = 1; j <= N; j++)
110 if (id0[i][j] != -1)
111 bfs(i, j, d[id0[i][j]][id1[i][j]], id0[i][j]);
112
113 for (int i = 1, i0, i1; i < (1 << K); i++)
114 {
115 i0 = sta[i];
116 for (int j = 0; j < K; j++)
117 {
118 if ((i0 >> j)&1)
119 {
120 i1 = i0 - (1 << j);
121 for (int c0 = 0; c0 < cnt[j]; c0++)
122 {
123 if (i1 > 0)
124 {
125 for (int k = 0; k < K; k++)
126 if ((i1 >> k)&1)
127 for (int c1 = 0; c1 < cnt[k]; c1++)
128 if (d[j][c0][k][c1] != INF && f[i1][k][c1] != INF)
129 f[i0][j][c0] = min(f[i0][j][c0], f[i1][k][c1] + d[j][c0][k][c1] *(1 + C[i1]) + A[j]);
130 }
131 else if (dd[j][c0] != INF)
132 f[i0][j][c0] = min(f[i0][j][c0], dd[j][c0] + A[j]);
133 }
134 }
135 }
136 }
137 ans = INF;
138 for (int i = 0, k = (1 << K) - 1; i < K; i++)
139 for (int j = 0; j < cnt[i]; j++)
140 if (f[k][i][j] + dd[i][j] * (1 + C[k]) <= P && dd[i][j] != INF && f[k][i][j] != INF)
141 ans = min(ans, f[k][i][j] + dd[i][j] *(1 + C[k]));
142
143 if (ans != INF)
144 printf("%d\n", ans);
145 else
146 printf("Impossible\n");
147 }
148 return 0;
149