Fork me on GitHub

BFS(宽搜)

预备知识

队列

常见操作

  • 判断队列是否为空 q.empty()
  • push
  • pop

宽度优先搜索

二叉树的层次遍历

  1. 把当前点后面的所有点结构体加入队列中
  2. 最早扩展到的就是最短路径
  3. 记录最开始的坐标和结束的坐标

模板题 ACWing1101. 献给阿尔吉侬的花束

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 200 + 10;
char maze[maxn][maxn];
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int t;
int r, c;
int start_x, start_y;
int end_x, end_y;


struct Node
{
    int x;
    int y;
    int step;
}node[maxn * maxn];

bool check(int x, int y)
{
    if (x >= 0 && x < r && y >= 0 && y < c) return true;
    return false;
}

int bfs(int x, int y, int a, int b)
{
    maze[x][y] = '#';
    queue<Node> q;
    Node start = {x, y, 0};
    q.push(start);

    while (!q.empty())
    {
        Node now = q.front();
        q.pop();
        if (now.x == a && now.y == b) return now.step;
        for (int i = 0; i < 4; i ++ )
        {
            int dx = now.x + dir[i][0];
            int dy = now.y + dir[i][1];
            if (maze[dx][dy] != '#' && check(dx, dy))
            {
                Node ne = {dx, dy, now.step + 1};
                maze[dx][dy] = '#';  // 不走回头路
                q.push(ne);
            }
        }

    }
    return -1;
}

int main()
{
    cin >> t;
    while (t--)
    {
        cin >> r >> c;
        memset(maze, 0, sizeof(maze));
        for (int i = 0; i < r; i ++ ) scanf("%s", maze[i]);
        
        for (int i = 0; i < r; i ++ )
        {
            for (int j = 0; j < c; j ++ )
            {
                if (maze[i][j] == 'S')
                {
                    start_x = i;
                    start_y = j;
                }
                if (maze[i][j] == 'E')
                {
                    end_x = i;
                    end_y = j;
                }
            }
        }
        int res = bfs(start_x, start_y, end_x, end_y);
        if (res != -1) cout << res << endl;
        else cout << "oop!" << endl;
    }
}

hdoj 1495非常可乐

有几个问题解决不了:

  • 怎么判断现在是处于哪个杯子
  • 怎么判断它用了这个杯子

二维就够了,因为加起来是固定的。这里指的是我们自己创建的三维判断矩阵

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int v[5];
int sign[110][110][100];
struct cup //记录遍历中3个水杯容藏可乐情况
{
    int v[5];
    int step;
} temp;

void pour(int a, int b) //倒水函数,把a杯子中的可乐倒到b杯子中
{
    int sum = temp.v[a] + temp.v[b];
    if (sum >= v[b])
        temp.v[b] = v[b];
    else
        temp.v[b] = sum;
    temp.v[a] = sum - temp.v[b];
}

void bfs()
{
    int i, j;
    queue<cup> q;
    cup cnt;
    cnt.v[1] = v[1];
    cnt.v[2] = 0;
    cnt.v[3] = 0;
    cnt.step = 0;
    q.push(cnt);
    memset(sign, 0, sizeof(sign));
    sign[v[1]][0][0] = 1;
    while (!q.empty())
    {
        cnt = q.front();
        q.pop();
        if (cnt.v[1] == cnt.v[3] && cnt.v[2] == 0)
        {
            printf("%d\n", cnt.step);
            return;
        }
        for (i = 1; i < 4; ++i)
        {
            for (j = 1; j < 4; ++j)
            {
                if (i != j) //自己不倒水给自己
                {
                    temp = cnt; //每个水位情况都要把所有操作枚举一遍,所以都要赋值为原始水位情况
                    pour(i, j);
                    if (!sign[temp.v[1]][temp.v[2]][temp.v[3]])
                    {
                        temp.step++;
                        q.push(temp);
                        sign[temp.v[1]][temp.v[2]][temp.v[3]] = 1;
                    }
                }
            }
        }
    }
    printf("NO\n");
}

int main()
{
    while (scanf("%d%d%d", &v[1], &v[2], &v[3]) && v[1] || v[2] || v[3])
    {
        if (v[2] > v[3])
        {
            int t = v[2];
            v[2] = v[3];
            v[3] = t;
        }
        bfs();
    }
    return 0;
}

最先出现的目标是最少的次数

隐式图

优先队列priority queue

hdoj 1242 rescue

优先队列方法

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <queue>
#define MAXN 10000
using namespace std;
char map[1100][1100];
int vis[1100][1100];
int n, m;
int mi;
int sx, sy, ex, ey;
int dx[5] = {1, -1, 0, 0};
int dy[5] = {0, 0, 1, -1};
struct st
{
    int x;
    int y;
    int time;
    bool friend operator<(st a, st b)
    {
        return a.time > b.time;
    }
};
bool judge(st a)
{
    if (a.x < 0 || a.x >= n || a.y < 0 || a.y >= m || map[a.x][a.y] == '#' || vis[a.x][a.y])
        return false;
    return true;
}
int bfs(int x, int y)
{
    priority_queue<st> q;
    while (!q.empty())
        q.pop();
    st a;
    a.x = x;
    a.y = y;
    a.time = 0;
    vis[x][y] = 1;
    q.push(a);
    while (!q.empty())
    {
        st b = q.top();
        q.pop();
        if (map[b.x][b.y] == 'a')
            return b.time;
        for (int i = 0; i < 4; i++)
        {
            st end;
            end.x = b.x + dx[i];
            end.y = b.y + dy[i];
            end.time = b.time;
            if (judge(end))
            {
                if (map[end.x][end.y] == 'x')
                    end.time++;
                end.time++;
                q.push(end);
                vis[end.x][end.y] = 1;
            }
        }
    }
    return 0;
}
int main()
{
    while (~scanf("%d%d", &n, &m))
    {
        memset(map, 0, sizeof(map));
        for (int i = 0; i < n; i++)
        {
            scanf("%s", map[i]);
        }
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
            {
                if (map[i][j] == 'r')
                {
                    memset(vis, 0, sizeof(vis));
                    int ans = bfs(i, j);
                    if (ans < mi)
                        mi = ans;
                }
            }
        memset(vis, 0, sizeof(vis));
        if (mi == 0)
            printf("Poor ANGEL has to stay in the prison all his life.\n");
        else
            printf("%d\n", mi);
    }
    return 0;
}

老刘说了一句话,你们在掉了几百块钱很伤心,但是很多人不来我的课。其实我讲课几百块钱一小时。你想交钱我还不一定教

定义好一类规则就行了,长得最帅的出去,全部都出去了

优先队列其实是一个大顶堆,什么是堆呢?堆就是一个拟满二叉树,最后一层的上面全是满的。最后一层全部靠左

前缀编码里面没有前缀

我去找老师---学生找到我

在一个命名空间可以少打两次

greater表示小顶堆

硬着头皮写,问同学

不理解不要写上去,为每一句话负责

收获信息港

剪枝优化,动态规划和搜索都是最优的子问题

posted @ 2020-04-12 15:26  WalterJ726  阅读(149)  评论(0编辑  收藏  举报