Input第一行两个整数N和M,为矩阵的边长。 第二行一个整数D,为豆子的总个数。 第三行包含D个整数V1到VD,分别为每颗豆子的分值。 接着N行有一个N×M的字符矩阵来描述游戏矩阵状态,0表示空格,#表示障碍物。而数字1到9分别表示对应编号的豆子。
Output仅包含一个整数,为最高可能获得的分值。
Sample Input
3 8 3
30 -100 30
00000000
010203#0
00000000
Sample Output
38
数据范围:
50%的数据满足1≤D≤3。
100%的数据满足1≤D≤9,1≤N, M≤10,-10000≤Vi≤10000。
分析:这个题真是恶心啊。卡了我好几节课。
题意就不说了……
①先来说一下如何判断多边形能否围住豆豆,我们从豆豆向右引一条射线,判断和多边形有几个交点,如果有奇数个说明豆豆在里面。
但是有可能会出现射线和一条边重合的情况,点是在多边形里的,可这样判断,点是在外面的。
由于我们是向右引的,我们只需要当物体上下移动的时候判断,这样不会出现重合的情况,豆豆只会跨过多边形的边。
②这道题该怎么做?看数据的话很显然是状压dp。定义f[x][y][s]表示从(x,y)出发的点,状态为s(围住了哪几个豆豆),围成的最短的多边形的长度。我们要预处理出来每个状态下围住豆豆的分数v[s]
从当前的状态如何推得下一个状态?我们需要判断下一个走到下一个格子时,每个豆豆是否还在多边形里面。根据①可以知道豆豆是否还在里面。
如果改变了,就让状态s的第i位取反,表示豆豆在里面或者不在里面。
如何得到f[x][y][s]? 我们可以跑bfs或者spfa,由于从起点遍历整个图,路径是可达的,必然可以回到起点。
最后再求出来v[s]-f[x][y][s]的最大值就行了。

1 /************************************************************************* 2 > File Name: s.cpp 3 > Author: LiuGeXian 4 > Mail: 1019630230@qq.com 5 > Created Time: 2020/4/14 18:47:59 6 ************************************************************************/ 7 #include <bits/stdc++.h> 8 const int maxn = 11; 9 using namespace std; 10 struct Node{ 11 int x, y, z; 12 Node(int a, int b, int c){ 13 x = a; 14 y = b; 15 z = c; 16 } 17 }; 18 int dx[5] = {0, 0, 1, -1}; 19 int dy[5] = {1, -1, 0, 0}; 20 int Max, f[maxn][maxn][1 << maxn], ans = -1, p[maxn]; 21 int d, n, m, g[maxn][maxn], px[maxn], py[maxn], v[1 << maxn], vis[maxn][maxn][1 << maxn]; 22 inline int Jud(int ax,int ay,int bx,int by,int az){ 23 for(int i = 1; i <= d; i++){ 24 if(((ax == px[i] && bx < px[i]) || (ax < px[i] && bx == px[i])) && by>py[i]){ 25 az ^= (1<<(i-1)); 26 } 27 } 28 return az; 29 } 30 int t; 31 inline void F(int x, int y){ 32 queue<Node> q; 33 q.push((Node){x, y, 0}); 34 memset(f, 0x3f, sizeof(f)); 35 memset(vis, 0, sizeof(vis)); 36 f[x][y][0] = 0; 37 while (q.size()){ 38 int ax = q.front().x; 39 int ay = q.front().y; 40 int az = q.front().z; 41 vis[ax][ay][az] = 0; 42 q.pop(); 43 for (int k = 0; k < 4; k++){ 44 int bx = ax + dx[k]; 45 int by = ay + dy[k]; 46 int bz = az; 47 if (bx < 1 || by < 1 || bx > n || by > m) continue; 48 if (g[bx][by]) continue; 49 if (k >= 2) bz = Jud(ax, ay, bx, by, az); 50 if (f[ax][ay][az]+1 < f[bx][by][bz]){ 51 f[bx][by][bz] = f[ax][ay][az] + 1; 52 if (!vis[bx][by][bz]) 53 vis[bx][by][bz] = 1; 54 q.push((Node){bx, by, bz}); 55 } 56 } 57 } 58 for (int s = 0; s < Max; s++){ 59 ans = max(ans, v[s] - f[x][y][s]); 60 } 61 } 62 int main(){ 63 scanf("%d%d", &n, &m); 64 scanf("%d", &d); 65 Max = 1 << d; 66 for (int i = 1; i <= d; i++) scanf("%d", &p[i]); 67 for (int i = 0; i < Max; i++){ 68 for (int j = 1; j <= d; j++){ 69 if (i &(1 << (j-1))) v[i] += p[j]; 70 } 71 } 72 for (int i = 1; i <= n; i++){ 73 for (int j = 1; j <= m; j++){ 74 char ch; 75 scanf(" %c", &ch); 76 if (ch == '#') g[i][j] = -1; 77 else if (ch == '0') g[i][j] = 0; 78 else { 79 int num = ch - '0'; 80 g[i][j] = num; 81 px[num] = i; 82 py[num] = j; 83 } 84 } 85 } 86 for (int i = 1; i <= n; i++){ 87 for (int j = 1; j <= m; j++){ 88 if (!g[i][j]) F(i, j); 89 } 90 } 91 cout << ans; 92 return 0; 93 }