洛谷P2566[SCOI2009]围豆豆

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: [email protected] 
 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 }
View Code

猜你喜欢

转载自www.cnblogs.com/ghosh/p/12710191.html