一、Problem
《西遊記》是中國文學四大經典小說之一。 它是明代吳承恩寫的。 在這部小說中,孫悟空、豬豬八戒和沙僧護送唐僧到印度獲取佛教文本。
在旅途中,唐僧經常被惡魔俘虜。 大多數惡魔都想吃唐僧才能長生不老,但有些女惡魔只是想嫁給他,因爲他很帥。 所以,對抗惡魔和拯救蒙唐是孫悟空的主要工作。
有一次,唐僧被惡魔白骨捕獲。 白骨住在一座宮殿裏,她把唐僧銬在一個房間裏。 孫悟空設法進了皇宮… 但要拯救唐僧,孫悟空可能需要得到一些鑰匙,並殺死蛇的方式。
宮殿可以被描述爲一個人物的矩陣。 每個角色代表一個房間。在矩陣中,‘K’代表孫悟空的原始位置,‘T’代表唐僧的位置,‘S’代表一個有蛇的房間。 請注意,宮殿裏只有一條“K”和一條“T”,最多有五條蛇。 ‘.’ 意思是一個乾淨的房間,以及 ‘#’ 意味着一個致命的房間,孫悟空無法進入。
房間裏可能會有一些不同種類的鑰匙散落在房間裏,一個房間裏最多隻有一把鑰匙。 最多有9種鑰匙。 有鑰匙的房間用一個數字(從‘1’到‘9’)表示。 例如,“1”是指帶有第一類鑰匙的房間,“2”是指帶有第二類鑰匙的房間,“3”是指帶有第三類鑰匙的房間…等等。 爲了拯救唐僧,孫悟空必須得到各種鑰匙(換句話說,每種至少有一個鑰匙)。
每一步,孫悟空都可以向四個方向(北、西、南、東)移動到相鄰的房間(致命的房間除外),每一步都花了他一分鐘。如果他進入了一個潛逃的房間,他必須殺死蛇。 殺死一條蛇也花了一分鐘。 如果孫悟空進入一個房間,那裏有一個類型N的鑰匙,孫會得到這個鑰匙,前提是當他已經有類型 1,類型 2 和類型 N-1 的鑰匙。 如果孫悟空得到了他所需要的所有鑰匙,進入唐僧被銬住的房間,救援任務就完成了。 如果孫悟空沒有得到足夠的鑰匙,他仍然可以通過唐僧的房間。孫悟空是一隻不耐煩的猴子,他想盡快救唐僧。 請找出孫悟空救唐僧所需的最短時間。
輸入
For each case, the first line includes two integers N and M(0 < N <= 100, 0<=M<=9), meaning that the palace is a N×N matrix and Sun Wukong needed M kinds of keys(kind 1, kind 2, … kind M).
Then the N×N matrix follows. The input ends with N = 0 and M = 0.
輸出
For each test case, print the minimum time (in minutes) Sun Wukong needed to save Tang Monk. If it’s impossible for Sun Wukong to complete the mission, print “impossible”(no quotes).
3 1
K.S
##1
1#T
3 1
K#T
.S#
1#.
3 2
K#T
.S.
21.
0 0
5
impossible
8
二、Solution
題意爲一個地圖,‘K’代表孫悟空的位置,也就是起點,‘T’代表唐僧的位置,數字‘1’‘2’等代表鑰匙類型,‘S’ 代表蛇,’#’ 不能走,題意的目的就是孫悟空去救唐僧,要求前提必須是拿到給定的 m 種鑰匙,才能去救唐僧,除了 '#‘ 的位置,其他位置都可以走(如果到達了唐僧的位置,但沒拿到給定的 m 種鑰匙,任務也沒法完成,必須得拿到 m 鍾鑰匙)。到達 ‘S’ 位置,要多花一分鐘殺死蛇,其他位置走一步花一分鐘,問最少花多少分鐘才能解救唐僧,如果不能,輸出impossible.
方法一:bfs + SC
本題難點:
- Q1:如何標記蛇精已經殺死還是沒死?
A1:使用 5 個二進制位即可。 - Q2:題目說道師傅的房間可經過多次,你怎麼知道經過的就是最短?
A2:只要鑰匙收集夠了,第一次經過就是最短。
未知錯誤:也不知道哪裏寫不對…
import java.util.*;
import java.math.*;
import java.io.*;
public class Main {
static int N, M;
static char[][] grid;
final static int[][] dir = { {1,0},{0,-1},{0,1},{-1,0} };
static boolean[][][][] vis;
static int sx, sy;
static int INF = 0x3f3f3f3f;
private static boolean inArea(int x, int y) {
return x >= 0 && x < N && y >= 0 && y < N;
}
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
while (true) {
N = sc.nextInt();
M = sc.nextInt();
if (N == 0 && M == 0)
break;
grid = new char[N][N];
vis = new boolean[N][N][1<<5 + 1][10]; //5條蛇 9把鑰匙
int snake = 0;
for (int i = 0; i < N; i++) {
String s = sc.next();
for (int j = 0; j < N; j++) {
grid[i][j] = s.charAt(j);
if (grid[i][j] == 'K') {
sx = i; sy = j;
} else if (grid[i][j] == 'S') {
grid[i][j] = (char) ('a' + snake);
snake++;
}
}
}
bfs();
System.out.println(res == INF ? "impossible" : res);
res = INF;
}
}
static int res = INF;
private static void bfs() {
Queue<Pos> q = new PriorityQueue<>((e1, e2) -> e1.d - e2.d);
q.add(new Pos(sx, sy, 0, 0, 0));
vis[sx][sy][0][0] = true;
while (!q.isEmpty()) {
Pos t = q.poll();
if (t.k == M && grid[t.x][t.y] == 'T') {
res = t.d;
return;
}
for (int i = 0; i < 4; i++) {
int tx = t.x + dir[i][0];
int ty = t.y + dir[i][1];
if (!inArea(tx, ty) || grid[tx][ty] == '#')
continue;
if ('1' <= grid[tx][ty] && grid[tx][ty] <= '9') { //鑰匙
t.d++;
int id = grid[tx][ty] - '0';
if (t.k + 1 == id)
t.k++;
} else if ('a' <= grid[tx][ty] && grid[tx][ty] <= 'z') { //蛇
int id = grid[tx][ty] - 'a';
if ((t.s & (1 << id)) == 1) { //死
t.d+=1;
} else {
t.d+=2;
}
t.s |= (1 << id);
} else {
t.d++;
}
if (!vis[tx][ty][t.s][t.k]) {
vis[tx][ty][t.s][t.k] = true;
q.add(new Pos(tx, ty, t.d, t.s, t.k));
}
}
}
}
static class Pos {
int x, y, d, k, s;
Pos(int _x, int _y, int _d, int _s, int _k) {
x = _x;y = _y;d = _d;k = _k;s = _s;
}
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
適當剪枝:
- 用一個
int[][][][] dist
來記錄每一步的信息,如果點.
時,如果當前步數比該點的步數還要多,那麼不更新該位置的 dist。
有時間再看看…
https://blog.csdn.net/sr_19930829/article/details/40352719
這裏