1 条题解
-
0
题目分析
这道题目描述了一个迷宫寻宝问题,主要特点包括:
- 迷宫结构:由字符矩阵表示的迷宫,包含墙壁、通道、石块和宝藏
- 移动规则:只能上下左右移动,不能穿过墙壁(*)
- 障碍物:数字石块(1-9)需要时间或炸药来清除
- 入口点:边界上的入口门(#或A-Z),部分带有炸药包
- 目标:从任意入口进入,找到到达宝藏($)的最短时间
解题思路
-
状态表示:
- 使用三元组(r,c,nTNT)表示状态:位置(r,c)和剩余炸药数量nTNT
- state[r][c][nTNT]记录到达该状态的最小时间
-
广度优先搜索(BFS):
- 从所有可能的入口门同时开始搜索
- 对每个状态考虑四种移动方向
- 遇到石块时有两种选择:使用炸药(时间+0)或等待(时间+石块硬度)
- 遇到宝藏时更新最短时间
-
关键优化:
- 状态剪枝:只保留到达同一位置和炸药数量时的最短时间
- 优先队列:可以改用Dijkstra算法处理不同时间消耗
标准代码实现
#include <iostream> // 添加这一行以使用std::getline #include <string> // 添加这一行以使用std::string #include<cstdio> #include<cstring> #include<ctype.h> using namespace std; const int maxn=1000000+3; const int maxr=110;//如果开105就是 runtimeerror const int maxc=110; int R,C; int dr[]={-1,1,0,0};//上,下,左,右 int dc[]={0,0,-1,1}; struct node { int r,c,nTNT; int time; node(){} node(int r,int c,int nTNT,int time):r(r),c(c),nTNT(nTNT),time(time){} }Q[maxn];//队列 int state[maxr][maxc][27];//记录到达该状态的最小时间 bool check(int r,int c,int nTNT,int t) { return (state[r][c][nTNT]==-1 || state[r][c][nTNT]>t); } char map[maxr][maxc];//保存地图信息 int BFS() { int front=0,tail=0; int ans=1000000; memset(state,-1,sizeof(state)); for(int i=0;i<R;i++) //边缘入口进队列 for(int j=0;j<C;j++)if(isupper(map[i][j]) || map[i][j]=='#') { Q[tail].r=i; Q[tail].c=j; Q[tail].nTNT=map[i][j]=='#'?0:map[i][j]-'A'+1; Q[tail].time=0; state[i][j][Q[tail].nTNT]=0; //错误1 这里漏了 tail++; } while(front<tail) { for(int d=0;d<4;d++) { int nr=Q[front].r+dr[d]; int nc=Q[front].c+dc[d]; int nTNT=Q[front].nTNT; int time=Q[front].time; if(nr>=1&&nr<=R-1&&nc>=1&&nc<=C-1&&map[nr][nc]!='*') { if(map[nr][nc]=='.' && check(nr,nc,nTNT,time)) { state[nr][nc][nTNT]=time; Q[tail]=node(nr,nc,nTNT,time); tail++;//也可以这么写进行剪枝 if(que[tail].time<ans) tail++; } else if(isdigit(map[nr][nc]))//数字墙 { if(nTNT>0 && check(nr,nc,nTNT-1,time))//炸开 { state[nr][nc][nTNT-1]=time; Q[tail]=node(nr,nc,nTNT-1,time); tail++;//也可以这么写进行剪枝 if(que[tail].time<ans) tail++; } if(check(nr,nc,nTNT,time+map[nr][nc]-'0'))//花时间打开 { state[nr][nc][nTNT]=time+map[nr][nc]-'0'; Q[tail]=node(nr,nc,nTNT,time+map[nr][nc]-'0'); tail++;//也可以这么写进行剪枝 if(que[tail].time<ans) tail++; } } else if(map[nr][nc]=='$') { if(ans>time) ans=time; } } } front++; } return ans; } int main() { while(true) { R=C=0; std::string line; // 用于存储读取的行 while(std::getline(std::cin, line)) // 使用std::getline替代gets { if(line.empty()) break; // 空行表示输入结束 if(line[0]=='-') return 0; // 以'-'开头的行表示程序结束 // 将读取的行复制到map数组中 std::strncpy(map[R], line.c_str(), maxc-1); map[R][maxc-1] = '\0'; // 确保字符串以空字符结尾 R++; } if(R == 0) break; // 如果没有读取到任何行,退出循环 C = std::strlen(map[0]); int ans=BFS(); if(ans==1000000) printf("IMPOSSIBLE\n"); else printf("%d\n",ans); } return 0; }
代码解析
-
数据结构:
State
结构体保存当前位置、剩余炸药和已用时间dist
数组记录到达各状态的最短时间
-
BFS实现:
- 初始化时将所有入口门加入队列
- 对每个状态扩展四种移动方向
- 处理普通通道、石块和宝藏三种情况
-
输入处理:
- 逐行读取地图直到空行或结束标记
- 处理换行符和边界条件
-
输出结果:
- 返回最短时间或IMPOSSIBLE
该解法通过状态空间搜索确保找到最优解,时间复杂度为O(R×C×T),其中T是最大炸药数量(26)。
- 1
信息
- ID
- 2347
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者