322 lines
9.8 KiB
C++
322 lines
9.8 KiB
C++
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#define MAXN 550
|
|
#define QSIZE (3 * 500 * 500)
|
|
|
|
enum posture {
|
|
pos_s,
|
|
pos_h,
|
|
pos_v
|
|
};
|
|
|
|
struct q_node {
|
|
int row;
|
|
int col;
|
|
posture pos;
|
|
};
|
|
|
|
int T;
|
|
int n, m;
|
|
int dist_s[MAXN][MAXN], dist_h[MAXN][MAXN], dist_v[MAXN][MAXN];
|
|
|
|
q_node q[QSIZE];
|
|
int q_head = 0;
|
|
int q_tail = 0;
|
|
|
|
void q_clear() {
|
|
q_head = 0;
|
|
q_tail = 0;
|
|
}
|
|
|
|
bool q_empty() {
|
|
return q_head == q_tail;
|
|
}
|
|
|
|
void enq(q_node node) {
|
|
q[q_tail] = node;
|
|
q_tail++;
|
|
q_tail %= QSIZE;
|
|
}
|
|
|
|
q_node deq() {
|
|
q_node ret = q[q_head];
|
|
q_head++;
|
|
q_head %= QSIZE;
|
|
return ret;
|
|
}
|
|
|
|
int start_row, start_col;
|
|
posture start_pos;
|
|
int end_row, end_col;
|
|
|
|
int map[MAXN][MAXN] = {0};
|
|
// 0 = wall
|
|
// 1 = ground
|
|
|
|
bool valid_pos(int row, int col, posture pos) {
|
|
if (row >= n || col >= m || row < 0 || col < 0) {
|
|
return false;
|
|
}
|
|
if (pos == pos_s) {
|
|
return map[row][col] > 0;
|
|
} else if (pos == pos_h) {
|
|
return map[row][col] > 0 && map[row][col + 1] > 0;
|
|
} else if (pos == pos_v) {
|
|
return map[row][col] > 0 && map[row + 1][col] > 0;
|
|
} else {
|
|
// should not be here
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int bfs() {
|
|
// init
|
|
q_clear();
|
|
for (int i = 0; i < n; ++i) {
|
|
for (int j = 0; j < m; ++j) {
|
|
dist_s[i][j] = -1;
|
|
dist_h[i][j] = -1;
|
|
dist_v[i][j] = -1;
|
|
}
|
|
}
|
|
|
|
if (start_pos == pos_s) {
|
|
dist_s[start_row][start_col] = 0;
|
|
} else if (start_pos == pos_h) {
|
|
dist_h[start_row][start_col] = 0;
|
|
} else if (start_pos == pos_v) {
|
|
dist_v[start_row][start_col] = 0;
|
|
}
|
|
|
|
q_node start_node = q_node {
|
|
.row = start_row,
|
|
.col = start_col,
|
|
.pos = start_pos,
|
|
};
|
|
|
|
enq(start_node);
|
|
|
|
while (!q_empty()) {
|
|
q_node cur_node = deq();
|
|
|
|
if (cur_node.row == end_row && cur_node.col == end_col && cur_node.pos == pos_s) {
|
|
return dist_s[end_row][end_col];
|
|
}
|
|
|
|
// printf("%d,%d, pos %d\n", cur_node.row, cur_node.col, cur_node.pos);
|
|
|
|
if (cur_node.pos == pos_s) {
|
|
int cur_dist = dist_s[cur_node.row][cur_node.col];
|
|
// left
|
|
if (valid_pos(cur_node.row, cur_node.col - 2, pos_h)) {
|
|
if (dist_h[cur_node.row][cur_node.col - 2] == -1) {
|
|
dist_h[cur_node.row][cur_node.col - 2] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row,
|
|
.col = cur_node.col - 2,
|
|
.pos = pos_h,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
|
|
// right
|
|
if (valid_pos(cur_node.row, cur_node.col + 1, pos_h)) {
|
|
if (dist_h[cur_node.row][cur_node.col + 1] == -1) {
|
|
dist_h[cur_node.row][cur_node.col + 1] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row,
|
|
.col = cur_node.col + 1,
|
|
.pos = pos_h,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
|
|
// up
|
|
if (valid_pos(cur_node.row - 2, cur_node.col, pos_v)) {
|
|
if (dist_v[cur_node.row - 2][cur_node.col] == -1) {
|
|
dist_v[cur_node.row - 2][cur_node.col] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row - 2,
|
|
.col = cur_node.col,
|
|
.pos = pos_v,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
|
|
// down
|
|
if (valid_pos(cur_node.row + 1, cur_node.col, pos_v)) {
|
|
if (dist_v[cur_node.row + 1][cur_node.col] == -1) {
|
|
dist_v[cur_node.row + 1][cur_node.col] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row + 1,
|
|
.col = cur_node.col,
|
|
.pos = pos_v,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
} else if (cur_node.pos == pos_h) {
|
|
int cur_dist = dist_h[cur_node.row][cur_node.col];
|
|
// left
|
|
if (valid_pos(cur_node.row, cur_node.col - 1, pos_s)) {
|
|
if (dist_s[cur_node.row][cur_node.col - 1] == -1) {
|
|
dist_s[cur_node.row][cur_node.col - 1] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row,
|
|
.col = cur_node.col - 1,
|
|
.pos = pos_s,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
|
|
// right
|
|
if (valid_pos(cur_node.row, cur_node.col + 2, pos_s)) {
|
|
if (dist_s[cur_node.row][cur_node.col + 2] == -1) {
|
|
dist_s[cur_node.row][cur_node.col + 2] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row,
|
|
.col = cur_node.col + 2,
|
|
.pos = pos_s,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
|
|
// up
|
|
if (valid_pos(cur_node.row - 1, cur_node.col, pos_h)) {
|
|
if (dist_h[cur_node.row - 1][cur_node.col] == -1) {
|
|
dist_h[cur_node.row - 1][cur_node.col] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row - 1,
|
|
.col = cur_node.col,
|
|
.pos = pos_h,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
|
|
// down
|
|
if (valid_pos(cur_node.row + 1, cur_node.col, pos_h)) {
|
|
if (dist_h[cur_node.row + 1][cur_node.col] == -1) {
|
|
dist_h[cur_node.row + 1][cur_node.col] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row + 1,
|
|
.col = cur_node.col,
|
|
.pos = pos_h,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
} else if (cur_node.pos == pos_v) {
|
|
int cur_dist = dist_v[cur_node.row][cur_node.col];
|
|
// left
|
|
if (valid_pos(cur_node.row, cur_node.col - 1, pos_v)) {
|
|
if (dist_v[cur_node.row][cur_node.col - 1] == -1) {
|
|
dist_v[cur_node.row][cur_node.col - 1] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row,
|
|
.col = cur_node.col - 1,
|
|
.pos = pos_v,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
|
|
// right
|
|
if (valid_pos(cur_node.row, cur_node.col + 1, pos_v)) {
|
|
if (dist_v[cur_node.row][cur_node.col + 1] == -1) {
|
|
dist_v[cur_node.row][cur_node.col + 1] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row,
|
|
.col = cur_node.col + 1,
|
|
.pos = pos_v,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
|
|
// up
|
|
if (valid_pos(cur_node.row - 1, cur_node.col, pos_s)) {
|
|
if (dist_s[cur_node.row - 1][cur_node.col] == -1) {
|
|
dist_s[cur_node.row - 1][cur_node.col] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row - 1,
|
|
.col = cur_node.col,
|
|
.pos = pos_s,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
|
|
// down
|
|
if (valid_pos(cur_node.row + 2, cur_node.col, pos_s)) {
|
|
if (dist_s[cur_node.row + 2][cur_node.col] == -1) {
|
|
dist_s[cur_node.row + 2][cur_node.col] = cur_dist + 1;
|
|
q_node new_node = q_node {
|
|
.row = cur_node.row + 2,
|
|
.col = cur_node.col,
|
|
.pos = pos_s,
|
|
};
|
|
enq(new_node);
|
|
}
|
|
}
|
|
} else {
|
|
// Should not be here
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int main() {
|
|
scanf("%d", &T);
|
|
for (int _ = 0; _ < T; ++_) {
|
|
// Initialize
|
|
memset(map, 0, sizeof(map));
|
|
bool found_start = false;
|
|
scanf("%d %d", &n, &m);
|
|
|
|
// Read in map
|
|
char linebuf[MAXN] = {0};
|
|
for (int i = 0; i < n; ++i) {
|
|
scanf("%s", linebuf);
|
|
for (int j = 0; j < m; ++j) {
|
|
if (linebuf[j] == '#') {
|
|
map[i][j] = 0;
|
|
} else if (linebuf[j] == '.' || linebuf[j] == 'E') {
|
|
map[i][j] = 1;
|
|
} else if (linebuf[j] == 'X') {
|
|
map[i][j] = 1;
|
|
if (found_start == false) {
|
|
start_row = i;
|
|
start_col = j;
|
|
start_pos = pos_s;
|
|
// Assume this pos, if there are more X then change
|
|
found_start = true;
|
|
} else {
|
|
if (j == start_col + 1 && i == start_row) {
|
|
start_pos = pos_h;
|
|
} else if (j == start_col && i == start_row + 1) {
|
|
start_pos = pos_v;
|
|
} else {
|
|
// Should not be here
|
|
}
|
|
}
|
|
} else if (linebuf[j] == 'O') {
|
|
map[i][j] = 1;
|
|
end_row = i;
|
|
end_col = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
int ans = bfs();
|
|
printf("%d\n", ans);
|
|
}
|
|
|
|
return 0;
|
|
} |