个人记录–BFS题

传教士与野蛮人

N名传教士和N个野蛮人同在一个小河渡口,渡口上只有一条可容M人的小船。问题的目标是要用这条小船把这2*N个人全部渡到对岸去,条件是在渡河的过程中,河两岸随时都保持传教士人数不少于野蛮人的人数,否则野蛮人会把处于少数的传教士吃掉。

//定义了一个Node结构体,包含三个整数字段:lm(左岸的传教士数量),ls(左岸的野人数量),以及step(到达当前状态所需的步骤数)。
struct Node {
    int lm;
    int ls;
    int step;
};

//L[i][j][k] 表示在左岸有i个传教士和j个野人还有船所在位置的状态。
//当i为0或等于n(传教士全部在一边),或i等于j时,该状态被标记为1;否则,标记为0。
void init(int n) {
    int i, j;
    for (i = 0; i <= n; ++i) {
        for (j = 0; j <= n; ++j) {
            if (i == 0 || i == n) {
                L[i][j][0] = L[i][j][1] = 1;
            } else if (i == j) {
                L[i][j][0] = L[i][j][1] = 1;
            } else {
                L[i][j][0] = L[i][j][1] = 0;
            }
        }
    }
}

int bfs(int n, int m) {
    Node queue[1000];
    int L[n + 1][n + 1][2];
    init(n);
    
    Node cur;
    int MinStep = -1;
    int head = 0, tail = 0;
    
    queue[tail].lm = n;
    queue[tail].ls = n;
    queue[tail++].step = 0;
    L[n][n][0] = 0;
    
    while (head < tail) {
        cur = queue[head++];
        //终止条件:满足条件(cur.step 是奇数,且左岸无传教士和野人),更新MinStep并跳出循环。
        if (cur.step % 2 == 1 && cur.lm == 0 && cur.ls == 0) {
            MinStep = cur.step;
            break;
        }
        //状态转移:检查新状态是否合法且未被访问过。如果是,则将新状态加入队列并更新 L 数组。
        for (i = m; i >= 0; i--) {
            for (j = m - i; j >= 0; j--) {
                if ((i + j > 0) && (i >= j || i == 0)) {
        //i + j > 0 确保每次至少有一个人移动;i >= j 确保移动的传教士数量不少于野人数量;i == 0 允许所有移动的人都是野人
                    if (cur.step % 2 == 0) { //只有船在左岸才运
                        if (i > cur.lm || j > cur.ls || L[cur.lm - i][cur.ls - j][1] == 0) continue;
                        //不能超过左岸实际上存在的数量;访问过的状态跳过
                        else {
                            L[cur.lm - i][cur.ls - j][1] = 0;
                            queue[tail].lm = cur.lm - i;
                            queue[tail].ls = cur.ls - j;
                            queue[tail++].step = cur.step + 1;
                        }
                    }
                }
            }
        }
    }
    return MiniStep;
};

Tank

N*M的矩阵,有坦克A和B,终点C和D。坦克A需要走到C,坦克B需要走到D。每经过一秒,坦克可以选择周围的8个方向任意移动一步,也可以选择原地不动。但是两个坦克不能相邻(周围8个方向),也不能去有墙的地方。问,最少需要多少秒,才能使两个坦克都达到目的地。

BFS 会首先探索所有可能的一步路径,然后是所有可能的两步路径,依此类推,直到找到一条有效路径。

#include <iostream>

using namespace std;

bool visit[9][9][9][9] = {0};
int s1i, s1j, s2i, s2j, e1i, e1j, e2i, e2j;
int map[9][9] = {0};// 没按题目,题目是N*M,反正自己测试

int dir[9][2] = {{0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, 0}};
int head = 1, tail = 1;

struct tag {
    int x1;
    int y1;
    int x2;
    int y2;
    int step;
} queue[100000];

// 不撞墙
bool isValid(int x, int y) {
    return map[x][y] != -1;
}

// 不相邻
bool isSafe(int x1, int y1, int x2, int y2) {
    return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) > 2;
}

int bfs() {
    //初始化
    queue[tail++] = {s1i, s1j, s2i, s2j, 0};
    visit[s1i][s1j][s2i][s2j] = 1;

    while (head < tail) {
        tag cur = queue[head++];
        if (cur.x1 == e1i && cur.y1 == e1j && cur.x2 == e2i && cur.y2 == e2j) {
            return cur.step;
        }

        for (int k1 = 0; k1 < 9; k1++) {
            int x1 = cur.x1 + dir[k1][0];
            int y1 = cur.y1 + dir[k1][1];
            if (!isValid(x1, y1)) continue;

            for (int k2 = 0; k2 < 9; k2++) {
                int x2 = cur.x2 + dir[k2][0];
                int y2 = cur.y2 + dir[k2][1];
                if (!isValid(x2, y2)) continue;
                if (!isSafe(x1, y1, x2, y2)) continue;
                if (visit[x1][y1][x2][y2]) continue;

                visit[x1][y1][x2][y2] = 1;
                queue[tail++] = {x1, y1, x2, y2, cur.step + 1};
            }
        }
    }
    return -1;
}

int main() {
    // 初始化地图(用于验证的,随便创建的地图)
    for (int z = 0; z <= 9; z++) {
        map[0][z] = -1;
        map[z][0] = -1;
        map[9][z] = -1;
        map[z][9] = -1;
    }

    cout << "Please input s1i, s1j, s2i, s2j:";
    cin >> s1i >> s1j >> s2i >> s2j;
    cout << "Please input e1i, e1j, e2i, e2j:";
    cin >> e1i >> e1j >> e2i >> e2j;

    int s = bfs();
    cout << "The minimum seconds = " << s << endl;

    return 0;
}

 

 

版权声明:
作者:shawn
链接:https://blog.shawn.chat/%e4%b8%aa%e4%ba%ba%e8%ae%b0%e5%bd%95-bfs%e9%a2%98/
来源:Peng的小屋
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录