1601 - The Morning after Halloween(BFS)

45 篇文章 0 订阅
44 篇文章 0 订阅

该题时限还是比较宽的,但是如果纯BFS还是会超时,所以要注意题目中的暗示 :任何一个2*2子网格中至少有一个障碍格 。  这表明障碍格有很多,那么重复搜索这些障碍格将会造成极大的浪费(因为我们开了三维数组记录三个鬼的状态,格子越多,状态也会以三次方的速度增加)。  所以我们可以将不是障碍的格子提出来再建一张图,用邻接表的方式。

那么怎么来建图呢? 受坐标离散化的启发,我们可以将每一个有用的格子映射成一个数字 ,作为它的标号 ,然后就可以方便的处理了 。

细节见代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 260;
int w,h,n,d[maxn][maxn][maxn],s[5],t[5],deg[maxn],g[maxn][maxn];
char a[20][20];
int dx[] = { 0,1,0,-1,0 };
int dy[] = { 1,0,-1,0,0 };
struct node{
    int a,b,c;
    node(int a=0,int b=0,int c=0) : a(a),b(b),c(c) {}
};
bool conflict(int a,int b,int a2,int b2) {
    return a2 == b2 || (a2 == b && a == b2); //两个鬼移动到同一个地方,或者移动到对方的地方
}
int bfs() {
    queue<node> q;
    memset(d,-1,sizeof(d));
    q.push(node(s[0],s[1],s[2]));
    d[s[0]][s[1]][s[2]] = 0;
    while(!q.empty()) {
        node u = q.front(); q.pop();
        if(u.a == t[0] && u.b == t[1] && u.c == t[2]) return d[u.a][u.b][u.c];
        for(int i=0;i<deg[u.a];i++) {
            int a2 = g[u.a][i];
            for(int j=0;j<deg[u.b];j++) {
                int b2 = g[u.b][j];
                if(conflict(u.a,u.b,a2,b2)) continue;
                for(int k=0;k<deg[u.c];k++) {
                    int c2 = g[u.c][k];
                    if(conflict(u.a,u.c,a2,c2)) continue;
                    if(conflict(u.b,u.c,b2,c2)) continue;
                    if(d[a2][b2][c2] != -1) continue;
                    d[a2][b2][c2] = d[u.a][u.b][u.c] + 1;
                    q.push(node(a2,b2,c2));
                }
            }
        }
    }
    return -1;
}
int main() {
    while(~scanf("%d%d%d",&w,&h,&n)) {
        if(!w && !h && !n) return 0;
        char c = getchar(); c = getchar();
        for(int i=0;i<h;i++) gets(a[i]);
        int cnt = 0,x[maxn],y[maxn],id[20][20];
        for(int i=0;i<h;i++)
            for(int j=0;j<w;j++) {
                if(a[i][j] != '#') {
                    x[cnt] = i; y[cnt] = j; id[i][j] = cnt;
                    if(islower(a[i][j])) s[a[i][j]-'a'] = cnt;//鬼的初始位置
                    else if(isupper(a[i][j])) t[a[i][j]-'A'] = cnt;//鬼的终止位置
                    ++cnt;
                }
            }
        for(int i=0;i<cnt;i++) {
            deg[i] = 0;
            for(int dir = 0; dir < 5; dir++) {
                int nx = dx[dir]+x[i] , ny = dy[dir]+y[i];
                if(a[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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值