LCEZ-2.18 开学测试 T3 密室逃脱 题解
题目描述
即使 Czhou 没有派出最强篮球阵容,机房篮球队还是暴虐了校篮球队。为了不打击校篮球队信心, Czhou 决定改变训练后的活动。近来,江大掌门的徒弟徒孙们纷纷事业有成,回到母校为机房捐钱捐物。财大气粗的机房组收回了五层六层的所有教室。 Czhou 决定将六层的教室改造为智能密室逃脱活动室。
每天傍晚,神牛们可以依次逐个进入游玩。我们简单的将教室分割为 \(n×n\) 个房间,\(K\) 是你初始所在房间,\(T\) 是你最终逃脱的房间。如果你想要逃脱房间,你必须依次找到m把钥匙。我们假定你从一个房间进入另一个房间需要花费 1 的时间。当然某些房间有些特殊的问题(地图上 \(S\) 表示)需要回答才能通过,对于机智的众牛们来说,这些问题根本不是问题。我们假定众牛们花费 1 的时间解决问题。(主要是出题的人表述不清,导致众牛理解困难;当然问题只需要回答一次,下次再次进入房间不需要回答了)
输入格式
第一行两个数字 \(n\),\(m\)
接下来 \(n×n\) 描述地图
输出格式
需要最少时间逃脱密室。若无解输出 impossible
。
输入 #1
3 1
K.S
##1
1#T
输出 #1
5
输入 #2
3 1
K#T
.S#
1#.
输出 #2
impossible
输入 #3
3 3
K#T
.S.
21.
输出 #3
8
样例3说明
要先取钥匙1,再取钥匙2。地图上可能有多个同一种钥匙,#为墙壁即不可走。
数据范围
\(0<N\le 100\), \(0\le M\le 9\),\(S\) 很小。
解题思路
考试时这道题没有给 \(S\) 的数据范围,导致这题不可做。
考试时我是依据 \(M\) 枚举的钥匙个数,求出需要跑最短路的次数,之后用 bfs 跑最短路,发现这是错误做法。
正解是通过 \(S\) 用 dfs 枚举走几个问题,之后用 bfs 跑最短路(走迷宫)。
一道非常基础的题,只要思路正确,会基本的深搜、广搜,再注意细节,就很容易切掉了。
代码
/*---------------------------------
*Title number: T3
*Creation date: 2021.2.18
*Author: EdisonBa
*-------------------------------*/
#include <头文件>
using namespace std;
typedef long long ll;
inline ll read(){}
const int inf = 100000000;
int ans = inf;
int n, m, cnt, x1, x2, y1, y2;
char a[105][105];
int f[105][105][15];
int qx[100005], qy[100005], qm[100005];
int xx[4] = {0, 0, 1, -1}, yy[4] = {1, -1, 0, 0};
int x[15], y[15];
void bfs()
{
memset(f, -1, sizeof(f));
qx[0] = x1;
qy[0] = y1;
int head = 0, tail = 1;
f[x1][y1][0] = 0;
while (head != tail)
{
int x = qx[head], y = qy[head], t = qm[head];
head++;
for (int i = 0; i < 4; i++)
{
int nowx = x + xx[i], nowy = y + yy[i], nowm = t;
if (nowx < 1 || nowy < 1 || nowx > n || nowy > n)
continue;
if (nowm + 1 == a[nowx][nowy] - '0')
nowm++;
if (a[nowx][nowy] == '#' || f[nowx][nowy][nowm] != -1)
continue;
f[nowx][nowy][nowm] = f[x][y][t] + 1;
qx[tail] = nowx;
qy[tail] = nowy;
qm[tail] = nowm;
tail++;
}
}
}
void dfs(int now, int k)
{
if (now == cnt + 1)
{
bfs();
if (f[x2][y2][m] != -1)
ans = min(ans, k + f[x2][y2][m]);
return;
}
a[x[now]][y[now]] = '.';
dfs(now + 1, k + 1);
a[x[now]][y[now]] = '#';
dfs(now + 1, k);
}
int main()
{
freopen("maze.in", "r", stdin);
freopen("maze.out", "w", stdout);
n = read();
m = read();
for (int i = 1; i <= n; i++)
{
scanf("%s", a[i] + 1);
for (int j = 1; j <= n; j++)
if (a[i][j] == 'K')
{
x1 = i;
y1 = j;
}
else if (a[i][j] == 'T')
{
x2 = i;
y2 = j;
}
else if (a[i][j] == 'S')
{
cnt++;
x[cnt] = i;
y[cnt] = j;
}
}
dfs(1, 0);
if (ans == inf)
puts("impossible");
else
printf("%d\n", ans);
return 0;
}
2021 CSP-S & NOIP \(RP++\)