【算法】复习搜索与图论

这篇具有很好参考价值的文章主要介绍了【算法】复习搜索与图论。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🍎 博客主页:🌙@披星戴月的贾维斯
🍎 欢迎关注:👍点赞🍃收藏🔥留言
🍇系列专栏:🌙 蓝桥杯
🌙请不要相信胜利就像山坡上的蒲公英一样唾手可得,但是请相信,世界上总有一些美好值得我们全力以赴,哪怕粉身碎骨!🌙
🍉一起加油,去追寻、去成为更好的自己!

提示:以下是本篇文章正文内容,下面案例可供参考


前言

    深度遍历算法(depth first search)俗称dfs和 广度优先遍历(broad first search)俗称bfs以及我们常听到的图论里面的最短路问题,借着这篇文章我们一起深入了解一下这些算法的逻辑和解法。

🍎1.中国象棋中的马的行动

题目描述

在中国象棋中,马的行动方式是“日”字形。假设我们有一个 8x8 的棋盘,棋盘的左上角是(0,0),右下角是(7,7)。马开始时位于给定的位置(x,y),你的任务是计算马需要多少步才能到达目标位置(a,b)。如果马不能到达目标位置,就返回-1。

注意:马只能按照“日”字形行动,即先向上或向下移动两步,然后向左或向右移动一步,或者先向左或向右移动两步,然后向上或向下移动一步。

输入格式

输入共两行,每行包含两个整数。第一行是马的初始位置(x,y),第二行是马的目标位置(a,b)。所有的整数都在0到7之间。

输出格式

输出一个整数,表示马到达目标位置需要的最少步数。如果不能到达,就输出-1。
输入输出样例
0 0;
7 7;

输出样例:
6

老规矩, 我们要养成一个好的写程序习惯,那就是先写思路,再写实现过程

解题思路:
    首先,我们可以通过看数据范围大致判断这一题用到的算法,数据范围才8,可以支持dfs,bfs,dp等等各种算法,而且我们读题可以知道,🐎的行动方式是“日”字形,即可以画图得出它的方向图
【算法】复习搜索与图论,C++初阶,算法手札,算法,图论,深度优先
即我们可以设置一个距离数组,通过bfs去枚举这八个方向,算出初始点到各个可能到达点的距离,我们通过队列来存储可能到达的下一个点,如果队列里面没有数字了就代表遍历结束,返回值。

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
#define x first
#define y second
bool st[10][10];
int d[10][10];
int a1, b1, a2, b2;
int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2}, dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};
int bfs(int x, int y)
{
    queue<pii> q;
    q.push({x, y});//把点放入队列
    st[x][y] = true;//标记
    while(q.size())
    {
        auto t = q.front();
        q.pop();
        
        if(t.x == a2 && t.y == b2) return d[a2][b2];//如果找到直接返回距离数组
        
        for(int i = 0; i < 8; i++)
        {
            int ax = t.x + dx[i], ay = t.y + dy[i];
            if(ax < 0 || ax > 7  || ay < 0 || ay > 7 || st[ax][ay] == true) continue;
            
            st[ax][ay] = true;
            d[ax][ay]=d[t.x][t.y]+1;
            q.push({ax, ay});
        }
        
    }

    return -1;//如果找不到就返回-1
}
int main ()
{
    cin >> a1 >> b1;
    cin >> a2 >> b2;
    int t = bfs(a1, b1);
    
    cout << t << endl; 

    return 0;
}

写法2:dfs深度搜索

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
#define x first
#define y second
bool st[10][10];
int dist[10][10];
int a1, b1, a2, b2;
int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2}, dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};
void dfs(int x, int y)
{
    if(x == a2 && y == b2) return;//判断结束条件

    for(int i = 0; i <= 7; i++)
    {
        int tx = x + dx[i];
        int ty = y + dy[i];

        if(tx < 0 || tx > 7 || ty < 0 || ty > 7)
            continue;

        if(dist[tx][ty] > dist[x][y] + 1)
        {
            dist[tx][ty] = dist[x][y] + 1;
            dfs(tx, ty);
        }
    }
    return;
}
int main ()
{
    cin >> a1 >> b1;
    cin >> a2 >> b2;

    memset(dist, 0x3f, sizeof dist); //先将方向数组置为0x3f
    dist[a1][b1] = 0;
    dfs(a1, b1);

    if(dist[a2][b2] == 0x3f3f3f3f) cout << "-1" << endl;//如果没有搜到就输出-1
    else cout << dist[a2][b2] << endl;//否则输出距离

    return 0;
}

学习搜索我还推荐大家去看走迷宫和红与黑这两题,都是比较经典的。

🍎2.Dijkstra求最短路 I(图论)

题目描述

由于题目复制会乱码,所以博主干脆用图片代替。
【算法】复习搜索与图论,C++初阶,算法手札,算法,图论,深度优先
图论问题和dp问题的区别

dp是选择下一个数(选择下一个状态)

图论是选择这个小的点去更新后继的节点
【算法】复习搜索与图论,C++初阶,算法手札,算法,图论,深度优先
如下图例子:
【算法】复习搜索与图论,C++初阶,算法手札,算法,图论,深度优先
在这个例子中,我们把已经确定的最短的距离标为绿色,这时候我们t = 2这个节点,发现3这个节点 的距离到原点是4大于2 + 1,更新3和节点1的最短距离。
代码示例:

dist数组存储的是第一个节点到第 j个节点的距离是累加的

#include<bits/stdc++.h>
using namespace std;
//存稠密图用邻接矩阵
const int N = 510;
int n, m;
int g[N][N];
int dist[N];
bool st[N];

int dijkstar()
{
    memset(dist, 0x3f, sizeof dist); // 1、先初始化距离
    dist[1] = 0; //1号点到自己的距离为0
    for(int i = 0; i < n; i++)
    {
        int t = -1;
        for(int j = 1; j <= n; j++) //遍历所有点
        {
            if(!st[j] && (t == -1 || dist[t] > dist[j]))//如果j没有遍历过和t == -1或者t这点的距离>j的距离,更新t
            t = j;
        }
        st[t] = true;
        for(int j = 1; j <= n; j++)
        {
            dist[j] = min(dist[j], dist[t] + g[t][j]);//g的ab是a 到b 点的距离
        }
    }
    if(dist[n] == 0x3f3f3f3f) return -1;
    else return dist[n];
    
}
int main ()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m; //n个点m条边
    
    memset(g, 0x3f, sizeof g);
    
    while(m --)
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = min(g[a][b], c);
    }
    int h = dijkstar();
    cout << h << endl;
    return 0;
}

🍎3.Dijkstra求最短路 II

【算法】复习搜索与图论,C++初阶,算法手札,算法,图论,深度优先

思路:n的数据范围从500 到了 1.5 * 10的五次方,数据量一下子变得很大,用邻接矩阵去存储很容易爆内存,而且会超时,所以要用邻接表去存。而且为了提高效率,我们要用优先级队列。
时间复杂度m*logn


#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
#define x first
#define y second

typedef pair<int, int> pii;
int h[N], ne[N], e[N], idx, w[N];
int n, m;
bool st[N];
int dist[N];
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] =idx++;
}
int dijkstart()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> q;
    q.push({0, 1}); //1号点,距离是0,编号是1
    while(q.size())
    {
        auto t = q.top();
        q.pop();
        int ver = t.y, d = t.x; 
        if(st[ver]) continue; //说明遍历过了
        st[ver] = true; //标记
        for(int i = h[ver]; i!= -1; i = ne[i])
        {
            int j = e[i];//当前节点
            if(dist[j] > d + w[i])
            {
                dist[j] = d + w[i];
                q.push({dist[j], j});
            }
        }
    }
    if(dist[n] == 0x3f3f3f3f) return -1;
    else return dist[n];
}
int main ()
{
    memset(h, -1, sizeof h);
    cin >> n >> m;
    
    while(m --)
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
    }
    int h = dijkstart();
    cout << h << endl;
    
    return 0;
}

🍎4. spfa求最短路

【算法】复习搜索与图论,C++初阶,算法手札,算法,图论,深度优先
如果说边的距离全部都是正的,我们用dijkstart算法,那么如果存在负边权,那么我们可以采用spfa算法,而且spfa算法效率会高很多,时间复杂度是0(n * m)。同样,我们可以用spfa算法解决之前dijkstart算法的题,spfa的写法很像上一道题,利用邻接表去存储,然后利用队列把距离短的点存储起来,然后去更新后继节点。但是我可能会比较嫌弃邻接表写法比较复杂,我们可以用vector<结构体>这样的形式来存储图。
代码示例:

#include<bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;
const int N = 1e5 + 10;
int n, m;
struct Node
{
     int node;
     int w;
};
int dist[N];
bool st[N];

vector<Node> g[N];//二维的数组
int spfa()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    queue<int> q; //队列存储所有待更新的点
    q.push(1); //把1号点放入队列
    st[1] = true;// st数组存当前这个点是否在队列当中
    
    while(q.size())
    {
        int t = q.front();//每次取出队头
        q.pop();
        st[t] = false;
        //更新所有领边
        for(int i = 0; i < g[t].size(); i ++)
        {
            int j = g[t][i].node;
            if(dist[j] > dist[t] + g[t][i].w)
            {
                dist[j] = dist[t] +  g[t][i].w;
                if(!st[j])
                {
                    q.push(j);
                    st[j] = true;
                }
            }
        }
    }
    return dist[n];
}
int main ()
{
    cin >> n >> m;
    
    while(m --)
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a].push_back({b, c});
    }
    int t = spfa();
    if(t == 0x3f3f3f3f) cout << "impossible";
    else cout << t << endl;
    
    return 0;
}

🍎总结

    本文和大家介绍了几题搜索和图论的题目,既帮助了自己复习,也希望对读者有所帮助!文章来源地址https://www.toymoban.com/news/detail-752210.html

到了这里,关于【算法】复习搜索与图论的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【算法导论】图论(图的基本概念,图上的深度优先搜索(DFS),广度优先搜索(BFS),最小生成树(MST)及Prim,Kruskal算法)

    图(Graph)是一种包含节点与节点的边的集合,记作G=(V,E),V是节点的集合,E是边的集合。 有向图 一个有向图G=(V,E),E中每个元素是V上的一个二值关系:一条从a出发的连向b的边e可以记作一个 有序 对e = (a,b) 。 无向图 一个无向图G=(V,E),E的每个元素e可以表示V上的一个 无序 对,记

    2024年02月03日
    浏览(32)
  • 搜索与图论 - 搜索与图在算法中的应用【中】

    目录 迪杰斯特拉算法Dijkstra  Dijkstra求最短路 I Dijkstra求最短路 II 贝尔曼-福特算法 bellman-ford 有边数限制的最短路 SPFA算法 spfa求最短路  spfa判断负环 Floyd Floyd求最短路   该算法不能存在负权边 思路: 初始化距离数组, dist[1] = 0, dist[i] = inf; for n次循环 每次循环确定一个min加

    2023年04月08日
    浏览(67)
  • 算法基础课-搜索与图论

    题目链接:842. 排列数字 - AcWing题库 思路:写的很好的题解AcWing 842. 排列数字--深度优先遍历代码+注释 - AcWing 也可以考虑使用c++自带的next_permutation函数直接秒了: 题目链接:844. 走迷宫 - AcWing题库 思路:由于bfs是一层一层扩展,所以能保证走到终点时,走过的距离最短,所

    2024年04月15日
    浏览(38)
  • 搜索与图论(acwing算法基础)

    排列数字 n皇后 走迷宫 单链表 点击跳转至例题 idx存的是指针 树与图的深度优先搜索 树的重心 每个节点都是一个单链表 模拟队列 hh = 0 , tt = -1 有向图的拓扑序列 都是从前指向后,即有向无环图(不能有环) 所有入度为0的点,都能排在前面的位置 删掉t-j的边,仅仅是j的入度

    2024年02月08日
    浏览(31)
  • 搜索与图论:匈牙利算法

    将所有点分成两个集合,使得所有边只出现在集合之间,就是二分图 二分图:一定不含有奇数个点数的环;可能包含长度为偶数的环, 不一定是连通图

    2024年02月08日
    浏览(29)
  • 搜索与图论2.2-Floyd算法

    (Floyd) 算法是一种可以快速求解图上所有顶点之间最短路径的算法。 (Bellman-Ford) 和 (Dijkstra) 算法求解的都是从一个起始点开始的最短路。如果想要求解图中所有顶点之间的最短路,就需要枚举每个点做为起点,这样十分低效。 (Floyd) 算法(也称 (Floyd-Warshall) 算法)处理用

    2024年02月08日
    浏览(23)
  • acwing算法基础之搜索与图论--kruskal算法

    kruskal算法的关键步骤为: 将所有边按照权重从小到大排序。 定义集合S,表示生成树。 枚举每条边(a,b,c),起点a,终点b,边长c。如果结点a和结点b不连通(用并查集来维护),则将这条边加入到集合S中。 kruskal算法的时间复杂度为O(mlogm),它用来解决稀疏图的最小生成树问题

    2024年02月05日
    浏览(32)
  • 【算法基础:搜索与图论】3.3 拓扑排序

    https://oi-wiki.org/graph/topo/ 本文主要学习拓扑排序相关知识。 拓扑排序的英文名是 Topological sorting。 拓扑排序要解决的问题是给一个 有向无环图 的 所有节点排序 。 我们可以拿大学每学期排课的例子来描述这个过程,比如学习大学课程中有:程序设计,算法语言,高等数学,

    2024年02月16日
    浏览(33)
  • 【算法基础:搜索与图论】3.2 树与图的dfs和bfs

    要学会建树、建图的通用方法。 dfs 和 bfs 的代码框架。 https://www.acwing.com/problem/content/848/ 在 dfs 的过程中,统计各个节点作为断点时的连通块最大值。 https://www.acwing.com/problem/content/849/ 看到最短距离就可以想到使用宽搜。 注意! :题目中说明了 a 和 b 表示存在一条从 a 走到

    2024年02月16日
    浏览(28)
  • Acwing-基础算法课笔记之搜索与图论

    bellman-ford算法适用于负权边的图,求 1 到 n 的最多经过k条边的最短距离。 如图所示: 1 2 3 dist 0 ∞ infty ∞ ∞ infty ∞ ⇓ Downarrow ⇓ 1 2 3 dist 0 1 ∞ infty ∞ ⇓ Downarrow ⇓ 1 2 3 dist 0 1 2 此过程中出现了串联的结果,所以是错误的,此时需要进行备份操作。 备份操作如下: 为了

    2024年01月20日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包