1.問題
王女は邪悪な者に捕らえられ、独房のどこかに抱かれていました。セルは、N * M(N、M <= 200)の行列で表されます。マトリックスの各項目は、道路(@)、壁(#)、および警備員(x)を表すことができます。
英雄的な騎士(r)が王女を一人で救うことにしました(a)。救助成功の表現は「騎士がお姫様の位置に着いた」と表現します。
王女のいる場所への道で警備員が遭遇する可能性があるため、騎士が警備員に会ったら、次に進むには警備員を殺さなければなりません。
今度は、騎士が上下左右に移動できると仮定します。ポジションの移動ごとに1単位時間、ガードを倒すには追加の単位時間が必要です。また、騎士はすべての警備員を殺すのに十分強いと仮定します。
セルマトリックス、マトリックス内のプリンセス、ナイト、ガードの位置を考慮して、レスキュー操作が成功するのにかかる最小時間を計算してください。
入力
1行目は整数Sで、入力データのグループ(複数の入力グループ)の数を示します。次に、S個のデータセットがあり、各データセットは次の形式で入力されます。
- 2つの整数はNとMを表します(N、M <= 200)。
- 次に、各行にM文字のN行があります。「@」は道路を表し、「a」は姫を表し、「r」は騎士を表し、「x」は警備員を表し、「#」は壁を表します。
アウトプット
レスキュー操作が成功すると、操作の最短時間を示す整数が出力されます。
成功しない場合は「不可能」を出力
样例输入
2
7 8
#@#####@
#@a#@@r@
#@@#x@@@
@@#@@#@#
#@@@##@@
@#@@@@@@
@@@@@@@@
13 40
@x@@##x@#x@x#xxxx##@#x@x@@#x#@#x#@@x@#@x
xx###x@x#@@##xx@@@#@x@@#x@xxx@@#x@#x@@x@
#@x#@x#x#@@##@@x#@xx#xxx@@x##@@@#@x@@x@x
@##x@@@x#xx#@@#xxxx#@@x@x@#@x@@@x@#@#x@#
@#xxxxx##@@x##x@xxx@@#x@x####@@@x#x##@#@
#xxx#@#x##xxxx@@#xx@@@x@xxx#@#xxx@x#####
#x@xxxx#@x@@@@##@x#xx#xxx@#xx#@#####x#@x
xx##@#@x##x##x#@x#@a#xx@##@#@##xx@#@@x@x
x#x#@x@#x#@##@xrx@x#xxxx@##x##xx#@#x@xx@
#x@@#@###x##x@x#@@#@@x@x@@xx@@@@##@@x@@x
x#xx@x###@xxx#@#x#@@###@#@##@x#@x@#@@#@@
#@#x@x#x#x###@x@@xxx####x@x##@x####xx#@x
#x#@x#x######@@#x@#xxxx#xx@@@#xx#x#####@
样例输出
13
7
二、Solution
方法1:bfs
元のアイデア: bfsのステップの昇順でノードの優先度キューを使用しますが、問題があります:騎士のいない道路が騎士よりもコストが高い場合、アルゴリズムは間違っています。
修正案:ステップが重ねられているので優先キューを使うのが正しい...
import java.util.*;
import java.math.*;
import java.io.*;
public class Main {
static int R, C;
static char[][] grid;
final static int[][] dir = { {1,0},{0,-1},{0,1},{-1,0} };
static int sx, sy, ex, ey;
private static boolean inArea(int x, int y) {
return x >= 0 && x < R && y >= 0 && y < C;
}
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int S = sc.nextInt();
while (S-- > 0) {
R = sc.nextInt();
C = sc.nextInt();
grid = new char[R][C];
for (int i = 0; i < R; i++) {
String s = sc.next();
for (int j = 0; j < C; j++) {
grid[i][j] = s.charAt(j);
if (grid[i][j] == 'a') ex = i; ey = j;
else if (grid[i][j] == 'r') sx = i; sy = j;
}
}
int res = bfs();
System.out.println(res == -1 ? "Impossible" : res);
}
}
private static int bfs() {
Queue<Pos> q= new PriorityQueue<>((e1, e2) -> e1.step - e2.step);
q.add(new Pos(sx, sy, 0));
grid[sx][sy] = '#';
while (!q.isEmpty()) {
Pos cur = q.poll();
if (cur.x == ex && cur.y == ey)
return cur.step;
for (int k = 0; k < 4; k++) {
int tx = cur.x + dir[k][0];
int ty = cur.y + dir[k][1];
if (!inArea(tx, ty) || grid[tx][ty] == '#')
continue;
if (grid[tx][ty] == 'x') {
q.add(new Pos(tx, ty, cur.step+2));
} else {
q.add(new Pos(tx, ty, cur.step+1));
}
grid[tx][ty] = '#';
}
}
return -1;
}
static class Pos {
int x, y, step;
public Pos(int _x, int _y, int _step) {
x = _x;
y = _y;
step = _step;
}
}
}
複雑さの分析
- 時間の複雑さ: 、
- スペースの複雑さ: 、
方法2:ナイーブbfs
- 各@間のエッジの重みは1、@とx間のエッジの重みは2です。
dist[ex][ey]
何度も通るかもしれませんが、私は最小のものしか取りません。- この場合、完全に網羅されていないため、通過していないポイントをマークすることはできません。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main {
static int R, C;
static char[][] grid;
final static int[][] dir = { {1,0},{0,-1},{0,1},{-1,0} };
static int sx, sy, ex, ey;
static int[][] dist;
static int INF = 0x3f3f3f3f;
private static boolean inArea(int x, int y) {
return x >= 0 && x < R && y >= 0 && y < C;
}
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
PrintWriter pw = new PrintWriter(System.out, true); //自动刷新
int S = sc.nextInt();
while (S-- > 0) {
R = sc.nextInt();
C = sc.nextInt();
grid = new char[R][C];
dist = new int[R][C];
for (int i = 0; i < R; i++) {
String s = sc.next();
for (int j = 0; j < C; j++) {
dist[i][j] = INF;
grid[i][j] = s.charAt(j);
if (grid[i][j] == 'a') {
ex = i; ey = j;
} else if (grid[i][j] == 'r') {
sx = i; sy = j;
}
}
}
bfs();
System.out.println(dist[ex][ey] == INF ? "Impossible" : dist[ex][ey]);
}
}
private static void bfs() {
Queue<Pos> q= new ArrayDeque<>();
q.add(new Pos(sx, sy));
dist[sx][sy] = 0;
while (!q.isEmpty()) {
Pos cur = q.poll();
for (int k = 0; k < 4; k++) {
int tx = cur.x + dir[k][0];
int ty = cur.y + dir[k][1];
if (!inArea(tx, ty) || grid[tx][ty] == '#')
continue;
int t = dist[cur.x][cur.y] + 1;
if (grid[tx][ty] == 'x')
t++;
if (dist[tx][ty] > t) {
dist[tx][ty] = t;
q.add(new Pos(tx, ty));
}
}
}
}
static class Pos {
int x, y;
public Pos(int _x, int _y) {
x = _x;
y = _y;
}
}
}
複雑さの分析
- 時間の複雑さ: 、
- スペースの複雑さ: 、