UVA 1601 双向BFS

但是我们还不是很清楚每一次的状态怎么储存?我们可以用一个结构体,将每次的位置存起来,但是这个程序中用了一个更好的储存方法:我们知道最大的格数是16*16个,也就是256个,那么我们转换为二进制表示就是8位数,那么我们可以使用24位的二进制表示啊!然后我们再进行解压缩,所以这就是很神奇的地方!

普通BFS

#include<iostream>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<sstream>
#include<cstdio>
#define INF 0x3f3f3f3f
//const int maxn = 1e6 + 5;
const double PI = acos(-1.0);
typedef long long ll;
using namespace std;

const int maxn = 150;
const int maxs = 20;
const int dx[] = { 1,-1,0,0,0 };
const int dy[] = { 0,0,1,-1,0 };

inline int ID(int a, int b, int c) {
    return (a << 16) | (b << 8) | c;
}

int s[3], t[3];

int deg[maxn];    //记录每个编号为i的空格周围可以走的步数
int G[maxn][5];   

inline bool conflict(int a, int b, int a2, int b2) {
    return    a2 == b2 || (a2 == b && b2 == a);
}

int d[maxn][maxn][maxn];

int bfs() {
    queue<int> q;
    memset(d, -1, sizeof d);
    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;
                    d[a2][b2][c2] = d[a][b][c] + 1;
                    q.push(ID(a2, b2, c2));
                }
            }
        }
    }
    return -1;
}

int main() {
    int w, h, n;

    while (scanf("%d%d%d", &w, &h, &n) == 3 && n) {
        char maze[20][20];
        for (int i = 0; i < h; i++) fgets(maze[i], 20, stdin);

        int cnt, x[maxn], y[maxn], id[maxs][maxs];
        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;
                    else if (isupper(maze[i][j])) t[maze[i][j] - ‘A‘] = cnt;
                    cnt++;
                }
        }

        for (int i = 0; i < cnt; i++) {
            deg[i] = 0;
            for (int dir = 0; dir < 5; dir++) {
                int xx = x[i] + dx[dir], yy = y[i] + dy[dir];
                if (maze[xx][yy] != ‘#‘) G[i][deg[i]++] = id[xx][yy];
            }
        }

        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;
}

双向BFS

#include<iostream>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<sstream>
#include<cstdio>
#define INF 0x3f3f3f3f
//const int maxn = 1e6 + 5;
const double PI = acos(-1.0);
typedef long long ll;
using namespace std;

const int maxn = 150;
const int maxs = 20;
const int dx[] = { 1,-1,0,0,0 };
const int dy[] = { 0,0,1,-1,0 };

inline int ID(int a, int b, int c) {
    return (a << 16) | (b << 8) | c;
}

int s[3], t[3];

int deg[maxn];    //记录每个编号为i的空格周围可以走的步数
int G[maxn][5];
char maze[maxn][maxn];
int color[maxn][maxn][maxn];

inline bool conflict(int a, int b, int a2, int b2) {
    //两个鬼是exchange位置(违反第2条)
    //两个鬼移动到同一个格子(违反第1条)
    return    a2 == b2 || (a2 == b && b2 == a);
}

int d1[maxn][maxn][maxn];

int bfs() {
    queue<int> qf;
    queue<int> qb;

    d1[s[0]][s[1]][s[2]] = 0;
    d1[t[0]][t[1]][t[2]] = 1;

    qf.push(ID(s[0], s[1], s[2]));
    qb.push(ID(t[0], t[1], t[2]));

    while (!qf.empty() || !qb.empty()) {
        int fnum = qf.size(), bnum = qb.size();
        while (fnum--) {
            int u = qf.front(); qf.pop();
            int a = (u >> 16) & 0xff, b = (u >> 8) & 0xff, c = u & 0xff;

            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) || conflict(b, c, b2, c2)) continue;
                        if (color[a2][b2][c2] == 0) {
                            d1[a2][b2][c2] = d1[a][b][c] + 1;
                            color[a2][b2][c2] = 1;
                            qf.push(ID(a2, b2, c2));
                        }
                        else if (color[a2][b2][c2] == 2) {
                            return d1[a][b][c] + d1[a2][b2][c2];
                        }
                    }
                }
            }
        }
        while (bnum--) {
            int u = qb.front(); qb.pop();
            int a = (u >> 16) & 0xff, b = (u >> 8) & 0xff, c = u & 0xff;

            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) || conflict(b, c, b2, c2)) continue;
                        if (color[a2][b2][c2] == 0) {
                            d1[a2][b2][c2] = d1[a][b][c] + 1;
                            color[a2][b2][c2] = 2;
                            qb.push(ID(a2, b2, c2));
                        }
                        else if (color[a2][b2][c2] == 1) {
                            return d1[a][b][c] + d1[a2][b2][c2];
                        }
                    }
                }
            }
        }
    }
    return -1;
}

int main() {
    int w, h, n;
    while (scanf("%d%d%d", &w, &h, &n) == 3, n) {
        for (int i = 0; i < h; i++) fgets(maze[i], 20, stdin);
        int cnt = 0;
        int x[maxn], y[maxn];
        int id[maxs][maxs];
        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;
                    else if (isupper(maze[i][j])) t[maze[i][j] - ‘A‘] = cnt;
                    cnt++;
                }
            }
        }

        for (int i = 0; i < cnt; i++) {
            for (int j = 0; j < 5; j++) {
                int xx = x[i] + dx[j], yy = y[i] + dy[j];
                if (maze[xx][yy] != ‘#‘) G[i][deg[i]++] = id[xx][yy];
            }
        }

        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++;
        }

        memset(d1, 0, sizeof d1);
        memset(color, 0, sizeof color);

        if (s[0] == t[0] && s[1] == t[1] && s[2] == t[2]) printf("0\n");
        else printf("%d\n", bfs());
    }
    return 0;
}

原文地址:https://www.cnblogs.com/hznumqf/p/12358464.html

时间: 2024-11-01 23:46:02

UVA 1601 双向BFS的相关文章

Colour Hash (Uva 704 双向bfs)

Colour Hash Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description This puzzle consists of two wheels. Both wheels can rotate both clock and counter-clockwise. They contain 21 coloured pieces, 10 of which

UVa 1601 || POJ 3523 The Morning after Halloween (BFS || 双向BFS &amp;&amp; 降维 &amp;&amp; 状压)

题意 :w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占用同一个位置,也不能在一步之内交换位置.输入保证所有空格连通,所有障碍格也连通,且任何一个2*2子网格中至少有一个障碍格.输出最少的步数.输入保证有解. 分析 :可以将当前所有小鬼的位置作为一个状态,然后模拟小鬼移动BFS拓展出其他可行状态并且顺带记录步数,直到所有的小鬼都到达终点.首先状态如何表示

[2016-02-24][UVA][1601][The Morning after Halloween]

时间:2016-02-24 15:49:41 星期三 题目编号:UVA 1601 题目大意:给定一个迷宫图,至多3个小写字母和等数目大写字符,求小写字母移动到大写字母的最少步数 迷宫宽度范围是4~16,字母个数是1~3, 分析:求最少步数,BFS,知道终点状态,可以用双向bfs优化 方法:BFS //单向bfs #include<iostream> #include<cstdio> #include<queue> #include<cstring> #inc

UVa1601 - The Morning after Halloween(单向+双向BFS)

给出一个最大为16×16的迷宫图和至多3个ghost的起始位置和目标位置,求最少经过几轮移动可以使三个ghost都到达目标位置.每轮移动中,每个ghost可以走一步,也可以原地不动,需要注意的是任意两个ghost不能在相同的位置,因此也不能出现任意两个ghost对穿,也就是原来是ab,移动之后是ba.每个迷宫图'#'表示墙,' '表示空地,小写字母表示ghost的起始位置,大写字母表示对应ghost的目标位置,比如'a'应该走到'A'.保证任意2×2的空间内都有一个'#'. 看起来就像是人数多了

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