噩梦(双向BFS)

给定一张N*M的地图,地图中有1个男孩,1个女孩和2个鬼。

字符“.”表示道路,字符“X”表示墙,字符“M”表示男孩的位置,字符“G”表示女孩的位置,字符“Z”表示鬼的位置。

男孩每秒可以移动3个单位距离,女孩每秒可以移动1个单位距离,男孩和女孩只能朝上下左右四个方向移动。

每个鬼占据的区域每秒可以向四周扩张2个单位距离,并且无视墙的阻挡,也就是在第k秒后所有与鬼的曼哈顿距离不超过2k的位置都会被鬼占领。

注意: 每一秒鬼会先扩展,扩展完毕后男孩和女孩才可以移动。

求在不进入鬼的占领区的前提下,男孩和女孩能否会合,若能会合,求出最短会合时间。

输入格式

第一行包含整数T,表示共有T组测试用例。

每组测试用例第一行包含两个整数N和M,表示地图的尺寸。

接下来N行每行M个字符,用来描绘整张地图的状况。(注意:地图中一定有且仅有1个男孩,1个女孩和2个鬼)

输出格式

每个测试用例输出一个整数S,表示最短会合时间。

如果无法会合则输出-1。

每个结果占一行。



emmmmm, 当时就打了个测试程序就回班了, 回来之后看到我的代码里有这个东西:

啊啊啊, 孟神, 你的算法进阶真不是我拿的啊。
进入正题--

求步数的话我们很容易想到BFS, 但这是两个人, 其实也很容易想到双向BFS, 创建两个队列, 在合法的状态下同时搜索, 当一个人搜索到另一个点人访问过的点时, 此时的步数就是最少步数;

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e5 + 100;
const int MAXM = 3e3 + 10;

template < typename T > inline void read(T &x) {
    x = 0; T ff = 1, ch = getchar();
    while(!isdigit(ch)) {
        if(ch == ‘-‘) ff = -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *=ff;
} 

template < typename T > inline void write(T x) {
    if(x < 0) putchar(‘-‘), x = -x;
    if(x > 9) write(x / 10);
    putchar(x % 10 + ‘0‘);
} 

int T, n, m;
int vis[MAXM][MAXM];
int dx[5] = {1, 0, -1, 0};
int dy[5] = {0, 1, 0, -1};
char ch[MAXM][MAXM];
pair < int, int > boy, girl,  ghost[2];

// 梁神我的算法进阶是不是在你那 -- msm 

inline bool check(int xx, int yy, int dis) {
    if(xx < 0 || xx >= n || yy < 0 || yy >= m || ch[xx][yy] == ‘X‘) return false;
    for(int i = 0; i < 2; ++i) {
        if(abs(xx - ghost[i].first) + abs(yy - ghost[i].second) <= 2 * dis) return false;
    }
    return true;
}

inline int BFS() {
    memset(vis, 0, sizeof(vis));
    queue < pair < int, int > > qb, qg;
    qb.push(boy);
    qg.push(girl);
    int dis = 0;
    while(!qb.empty() || !qg.empty()) {
        ++dis;
        for(int i = 0; i < 3; ++i) {
            int len = qb.size();
            for(int j = 0; j < len; ++j) {
                pair < int, int > x;
                x = qb.front();
                qb.pop();
                int a = x.first, b = x.second;
                if(!check(a, b, dis)) continue;
                for(int k = 0; k < 4; ++k) {
                    int u = a + dx[k], v = b + dy[k];
                    if(check(u, v, dis)) {
                        if(vis[u][v] == 2) return dis;
                        if(!vis[u][v]) {
                            vis[u][v] = 1;
                            qb.push({u, v});
                        }
                    }
                }
            }
        }
        int len = qg.size();
        for(int i = 0; i < len; ++i) {
            pair < int, int > x;
            x = qg.front();
            qg.pop();
            int a = x.first, b = x.second;
            if(!check(a, b, dis)) continue;
            for(int k = 0; k < 4; ++k) {
                int u = a + dx[k], v = b + dy[k];
                if(check(u, v, dis)) {
                    if(vis[u][v] == 1) return dis;
                    if(!vis[u][v]) {
                        vis[u][v] = 2;
                        qg.push({u, v});
                    }
                }
            }
        }

    }
    return -1;
}

int main() {
    read(T);
    while(T--) {
        read(n); read(m);
        for(int i = 0; i < n; ++i) {
            scanf("%s", ch[i]);
        }
        int tot = 0;
        for(int i = 0; i < n; ++i) {
            for(int j = 0; j < m; ++j) {
                if(ch[i][j] == ‘M‘) boy = {i, j};
                else if(ch[i][j] == ‘G‘) girl = {i, j};
                else if(ch[i][j] == ‘Z‘) ghost[tot++] = {i ,j};
            }
        }
        write(BFS());
        puts("");
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/AK-ls/p/11447289.html

时间: 2024-11-08 19:27:29

噩梦(双向BFS)的相关文章

Hdu1401-Solitaire(双向bfs)

Solitaire is a game played on a chessboard 8x8. The rows and columns of the chessboard are numbered from 1 to 8, from the top to the bottom and from left to right respectively.There are four identical pieces on the board. In one move it is allowed to

UVA-1604 Cubic Eight-Puzzle (双向BFS+状态压缩+限制搜索层数)

题目大意:立体的八数码问题,一次操作是滚动一次方块,问从初始状态到目标状态的最少滚动次数. 题目分析:这道题已知初始状态和目标状态,且又状态数目庞大,适宜用双向BFS.每个小方块有6种状态,整个大方格有9*6^8个状态.每个小方块用一位6进制数表示即可. 注意:状态转移时要谨慎,否则会出现意想不到的错误: 这道题的末状态有256(2^8)个,如果对搜索层数不加限制,即使双向BFS也会TLE的,当限制正向搜索15层逆向搜索15层至正向搜索27层反向搜索3层时都能AC(我下面贴出的程序是这样的),其

HDU1195 双向BFS(或BFS)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1195 , 双向BFS或者直接BFS也可以过. 其实这道题只是单向BFS就可以过的,但是为了练算法,所以还是用了双向BFS来写. 算法: 先预处理一下,从1111到9999的所有点进行构图(由于是1~9的,所以除去含有0元素的数字),能进行一次变换变成的数字则表示两点之间连通.然后从初态与目态两个点进行BFS,如果有轨迹重合的就返回路程和. 这里注意双向BFS要一层一层的进行搜索,不然的话会产生错误,

POJ1915Knight Moves(单向BFS + 双向BFS)

题目链接 单向bfs就是水题 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <queue> 6 using namespace std; 7 const int INF = 0x3f3f3f3f; 8 const int Max = 300 + 5; 9 struct Node 10 { 11 int

BFS、双向BFS和A*

BFS.双向BFS和A* Table of Contents 1. BFS 2. 双向BFS 3. A*算法 光说不练是无用的.我们从广为人知的POJ 2243这道题谈起:题目大意:给定一个起点和一个终点.按骑士的走法(走日字),从起点到终点的最少移动多少次 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2RraXJjaGhvZmY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/g

HDU 1043 Eight(双向BFS+康托展开)

http://acm.hdu.edu.cn/showproblem.php?pid=1043 题意:给出一个八数码,求出到达指定状态的路径. 思路:路径寻找问题.在这道题里用到的知识点挺多的.第一次用双向BFS来做. ①双向BFS 在单向BFS的基础上,多建一个从终止状态开始搜索的队列,当然这个时候需要两个vis[]辅助数组,分别记录两个队列的访问情况,当两个队列相遇时即可终止循环. ②康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[

POJ 1915-Knight Moves (单向BFS &amp;&amp; 双向BFS 比较)

题目链接:Knight Moves 研究了一下双向BFS,不是很难,和普通的BFS一样,双向BFS不过是从 起点和终点同时开始搜索,可减少搜索时间 当两条搜索路线相遇时,结束. 貌似有一年百度的招聘 笔试,就是双向BFS.... 下面,比较一下BFS 和 双向BFS的用时: BFS STL的queue可能会浪费一点时间 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstrin

第六章部分例题 双向bfs邻接表和邻接矩阵实现

Idealpath 双向bfs输出颜色,邻接矩阵实现 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <map> 6 #include <algorithm> 7 8 using namespace std; 9 10 const int maxn=10000; 11 const int inf=1

[NOIP2002]字串变换 T2 双向BFS

题目描述 已知有两个字串  A,B  及一组字串变换的规则(至多6个规则): A1?>B1 A2?>B2 规则的含义为:在  A$中的子串  A1可以变换为可以变换为B1.A2可以变换为可以变换为B2  -. 例如:A==′abcd′B='xyz' 变换规则为: 'abc'-> 'xu' 'ud'-> 'y' 'y'-> 'yz' 则此时,A可以经过一系列的变换变为可以经过一系列的变换变为B,其变换的过程为: 'abcd'-> 'xud'-> 'xy'->