The Morning after Halloween
直接BFS会超时,题目中提示过墙壁很多,那么可以将所有的空格提取出来做张图,然后记录每个空格周围的邻居,这样就不用每次都判断能不能走了。优化的话可以使用双向BFS,从每次正向(从开始位置搜索)搜索一次,反向(从目标位置搜索)搜索一次,如果有相同状态则找到最短路径。
BFS(800ms):
#include
using namespace std;
const int maxl = 20;
const int maxn = 150;
int w, h, n;
int deg[maxn];
int G[maxn][5];
int s[3], t[3];
int d[maxn][maxn][maxn];
int x[maxn], y[maxn], id[maxl][maxl];
char maze[maxl][maxl];
int dx[] = {0, 0, 0, -1, 1};
int dy[] = {0, 1, -1, 0, 0};
int ID(int a, int b, int c){
return (a<<16) | (b<<8) | c;
}
bool conflict(int a, int b, int a2, int b2){
return a2 == b2 || (a2 == b && b2 == a);
}
int BFS(){
memset(d, -1, sizeof(d));
queueq;
q.push(ID(s[0], s[1], s[2]));
d[s[0]][s[1]][s[2]] = 0;
while(!q.empty()){
int u = q.front(); q.pop();
int a = (u>>16) & 0xff, b = (u>>8) & 0xff, c = u & 0xff;
if(a == t[0] && b == t[1] && c == t[2]) return d[a][b][c];
for(int i = 0; i < deg[a]; i++){
int a2 = G[a][i];
for(int j = 0; j < deg[b]; j++){
int b2 = G[b][j];
if(conflict(a, b, a2, b2)) continue;
for(int k = 0; k < deg[c]; k++){
int c2 = G[c][k];
if(conflict(a, c, a2, c2)) continue;
if(conflict(b, c, b2, c2)) continue;
if(d[a2][b2][c2] != -1) continue;
q.push(ID(a2, b2, c2));
d[a2][b2][c2] = d[a][b][c] + 1;
}
}
}
}
return -1;
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
while(scanf("%d%d%d", &w, &h, &n) == 3 && w){
getchar();
for(int i = 0; i < h; i++)
fgets(maze[i], maxl, stdin);
int cnt = 0;
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
if(maze[i][j] != '#'){
x[cnt] = i, y[cnt] = j, id[i][j] = cnt;
if(islower(maze[i][j])) s[maze[i][j] - 'a'] = cnt;
if(isupper(maze[i][j])) t[maze[i][j] - 'A'] = cnt;
cnt++;
}
}
}
for(int i = 0; i < cnt; i++){
deg[i] = 0;
for(int j = 0; j < 5; j++){
int nx = x[i] + dx[j], ny = y[i] + dy[j];
if(maze[nx][ny] != '#'){ //题目中说了迷宫的最外面是墙 因此不用判断边界
G[i][deg[i]++] = id[nx][ny];
}
}
}
if(n <= 2){ deg[cnt] = 1; G[cnt][0] = cnt; s[2] = t[2] = cnt++; }
if(n <= 1){ deg[cnt] = 1; G[cnt][0] = cnt; s[1] = t[1] = cnt++; }
printf("%d\n", BFS());
}
return 0;
}
DBFS(双向广度优先搜索,520ms):
#include
using namespace std;
const int maxl = 20;
const int maxn = 150;
int w, h, n;
int deg[maxn];
int G[maxn][5];
int s[3], t[3];
int d[2][maxn][maxn][maxn];
int x[maxn], y[maxn], id[maxl][maxl];
int mark = 0;
char maze[maxl][maxl];
int dx[] = {0, 0, 0, -1, 1};
int dy[] = {0, 1, -1, 0, 0};
int ID(int a, int b, int c){
return (a<<16) | (b<<8) | c;
}
bool conflict(int a, int b, int a2, int b2){
return a2 == b2 || (a2 == b && b2 == a);
}
void expand(queue& q, int n){
int u = q.front(); q.pop();
int a = (u>>16) & 0xff, b = (u>>8) & 0xff, c = u & 0xff;
if(d[1-n][a][b][c] != -1) mark = d[1-n][a][b][c] + d[n][a][b][c];
for(int i = 0; i < deg[a]; i++){
int a2 = G[a][i];
for(int j = 0; j < deg[b]; j++){
int b2 = G[b][j];
if(conflict(a, b, a2, b2)) continue;
for(int k = 0; k < deg[c]; k++){
int c2 = G[c][k];
if(conflict(a, c, a2, c2)) continue;
if(conflict(b, c, b2, c2)) continue;
if(d[n][a2][b2][c2] != -1) continue;
int t = ID(a2, b2, c2);
q.push(t);
d[n][a2][b2][c2] = d[n][a][b][c] + 1;
}
}
}
}
int DBFS(){
memset(d, -1, sizeof(d));
queueq[2];
q[0].push(ID(s[0], s[1], s[2]));
d[0][s[0]][s[1]][s[2]] = 0;
q[1].push(ID(t[0], t[1], t[2]));
d[1][t[0]][t[1]][t[2]] = 0;
int order = 0;
mark = 0;
while(!q[0].empty() && !q[1].empty()){
order ? expand(q[0], 0) : expand(q[1], 1);
if(mark) return mark;
order = !order;
}
return -1;
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
while(scanf("%d%d%d", &w, &h, &n) == 3 && w){
getchar();
for(int i = 0; i < h; i++)
fgets(maze[i], maxl, stdin);
int cnt = 0;
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
if(maze[i][j] != '#'){
x[cnt] = i, y[cnt] = j, id[i][j] = cnt;
if(islower(maze[i][j])) s[maze[i][j] - 'a'] = cnt;
if(isupper(maze[i][j])) t[maze[i][j] - 'A'] = cnt;
cnt++;
}
}
}
for(int i = 0; i < cnt; i++){
deg[i] = 0;
for(int j = 0; j < 5; j++){
int nx = x[i] + dx[j], ny = y[i] + dy[j];
if(maze[nx][ny] != '#'){ //题目中说了迷宫的最外面是墙 因此不用判断边界
G[i][deg[i]++] = id[nx][ny];
}
}
}
if(n <= 2){ deg[cnt] = 1; G[cnt][0] = cnt; s[2] = t[2] = cnt++; }
if(n <= 1){ deg[cnt] = 1; G[cnt][0] = cnt; s[1] = t[1] = cnt++; }
printf("%d\n", DBFS());
}
return 0;
}