程设2021期末题H:哥斯拉大战金刚
原题:http://cxsjsx.openjudge.cn/2021finalpractise/H/
描述
众所周知,哥斯拉和金刚是时代仇敌,大战一触即发。金刚为了打败哥斯拉,要先前往地心空洞获得战斧。金刚现在所在之处可以被视为一个n*m的网格图,S表示金刚目前的位置,T表示地心空洞的入口,X表示障碍物,.表示平地。在前往地心空洞之前,金刚必须先获得一系列打开地心空洞的钥匙(在地图上通过数字1,2,…,k表示),并且获得i类钥匙的前提是金刚已经获得了1,2,…,i-1类钥匙,金刚在拿到地图上所有种类的钥匙之后即可前往地心空洞的入口。另外,同一种类的钥匙可能有多把,金刚只需获得其中任意一把即可。金刚每一步可以朝上下左右四个方向中的一个移动一格,值得注意的是,哥斯拉为了阻挠金刚的计划,还在地图上设置了q个陷阱(在网格图中用G表示),金刚第一次进入某个陷阱需要花费额外的一步来破坏陷阱(这之后该陷阱即可被视为平地)。为了更好的掌握全局,请你帮金刚计算到达地心空洞入口所需要花费的最少步数。输入数据保证有解。
输入
第一行输入两个整数n,m,表示网格图的大小。
接下来n行,每行输入m个字符,表示地图
1 ≤ n,m ≤ 100
1 ≤ k ≤ 9
1 ≤ q ≤ 7
输出
输出一行包含一个整数,表示金刚到达地心空洞入口所需要花费的最少步数。
样例输入
5 5 XX13X X.GXX S...T XXGXX ....2
样例输出
24
解法
思路:广搜题,属于较为复杂的一种,既要收集钥匙也要破坏陷阱。
状态包括:x,y坐标,keys表示现在收集的钥匙种数,fighted表示是否已经消灭陷阱,steps记录此时的步数,layout是陷阱的分布(用short变量表示)。
去重:xy坐标+钥匙+陷阱分布
地图上的标识有
- '.':平地;'X':障碍,不能通过;'T':终点;'S':起点;‘G’:陷阱;1~9的数字:钥匙
- 起点和没有拿完钥匙的终点,不能拿的钥匙,破坏完的陷阱都当做平地处理
代码如下:
1 #include <iostream> 2 #include <queue> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 struct point { 8 int x, y; 9 short keys; 10 short fighted; 11 int steps; 12 short layout; 13 point(int inx,int iny,short k,short f,int s, short l):x(inx),y(iny),keys(k),fighted(f),steps(s),layout(l){} 14 }; 15 char flags[105][105][10][130]; 16 int n, m; 17 int k, q; 18 char maze[105][105]; 19 vector<pair<int, int> >traps; 20 int dx[4] = { -1,1,0,0 }; 21 int dy[4] = { 0,0,-1,1 }; 22 int findTraps(int x, int y) { 23 for (int i = 0; i < q; i++) { 24 if (traps[i].first == x && traps[i].second == y) 25 return i; 26 } 27 } 28 int main() { 29 cin >> n >> m; 30 int startx, starty; 31 q = 0; 32 k = 0; 33 for (int i = 0; i < n; i++) { 34 for (int j = 0; j < m; j++) { 35 cin >> maze[i][j]; 36 if (maze[i][j] == 'S') { 37 startx = i; 38 starty = j; 39 } 40 if (maze[i][j] == 'G') { 41 q++; 42 traps.push_back(make_pair(i, j)); 43 } 44 if (maze[i][j] > '0'&&maze[i][j] <= '9') 45 k = max(k, maze[i][j] - '0'); 46 } 47 } 48 queue<point>myqueues; 49 short oriLayout = (1 << q) - 1; 50 myqueues.push(point(startx, starty, 0, 0, 0,oriLayout)); 51 memset(flags, 0, sizeof(flags)); 52 flags[startx][starty][0][oriLayout] = 1; 53 while (!myqueues.empty()) { 54 point top = myqueues.front(); 55 myqueues.pop(); 56 if (maze[top.x][top.y] == 'T'&&top.keys==k) { 57 cout << top.steps << endl; 58 break; 59 } 60 if (maze[top.x][top.y] == 'G'&&top.fighted == 0) { 61 int index = findTraps(top.x, top.y); 62 short layout = top.layout&(~(1 << index)); 63 myqueues.push(point(top.x, top.y, top.keys, 1, top.steps + 1, layout)); 64 flags[top.x][top.y][top.keys][layout] = 1; 65 continue; 66 } 67 for (int i = 0; i < 4; i++) { 68 int tx = top.x + dx[i]; 69 int ty = top.y + dy[i]; 70 if (tx < 0 || tx >= n || ty < 0 || ty >= m) 71 continue; 72 if (maze[tx][ty] == 'X') 73 continue; 74 else if (maze[tx][ty] == 'G') { 75 if (flags[tx][ty][top.keys][top.layout]) 76 continue; 77 int index = findTraps(tx, ty); 78 if ((top.layout >> index) & 1) //还没打 79 myqueues.push(point(tx, ty, top.keys, 0, top.steps + 1, top.layout)); 80 else 81 myqueues.push(point(tx, ty, top.keys, 1, top.steps + 1, top.layout)); 82 flags[tx][ty][top.keys][top.layout] = 1; 83 } 84 else if (maze[tx][ty] == '.'||maze[tx][ty]=='S'||maze[tx][ty]=='T') { 85 if (flags[tx][ty][top.keys][top.layout]) 86 continue; 87 myqueues.push(point(tx, ty, top.keys, 0, top.steps + 1, top.layout)); 88 flags[tx][ty][top.keys][top.layout] = 1; 89 } 90 else { 91 int key = maze[tx][ty] - '0'; 92 if (key == top.keys + 1) { 93 if (flags[tx][ty][key][top.layout]) 94 continue; 95 myqueues.push(point(tx, ty, key, 0, top.steps + 1, top.layout)); 96 flags[tx][ty][key][top.layout] = 1; 97 } 98 else { 99 if (flags[tx][ty][top.keys][top.layout]) 100 continue; 101 myqueues.push(point(tx, ty, top.keys, 0, top.steps + 1, top.layout)); 102 flags[tx][ty][top.keys][top.layout] = 1; 103 } 104 } 105 } 106 } 107 return 0; 108 }