搜索与图论(一)(深搜,广搜,树与图的存储遍历,拓扑排序)

这篇具有很好参考价值的文章主要介绍了搜索与图论(一)(深搜,广搜,树与图的存储遍历,拓扑排序)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、DFS

往深里搜,搜到叶子结点那里,回溯,到可以继续到叶子结点深搜的位置。

1、回溯一定要恢复现场

2、定义一个与当前递归层数有关的终止条件(题目要求的东西)

3、每层都用循环判断是否存在可以dfs的路

输出数字组合

#include<bits/stdc++.h>
//842排列数字 按照字典序将n个数
using namespace std;
const int N=1e5+10;
int path[N];//记录走过的路径
int st[N];//用来记录某个元素是否被用过
int n;
void dfs(int u)
{
    //先判断是否已经得到一个答案
    if(u==n)
    {
        for(int i=0;i<n;i++)cout<<path[i]<<" ";
        puts("");
        return;
    }
    for(int i=1;i<=n;i++)
    {
        if(!st[i])//剪枝的过程找到可以构成dfs路径的方向
        {
            st[i]=true;
            path[u]=i;
            dfs(u+1);
            path[i]=0;//恢复现场
            st[i]=false;
        }
    }
}
int main()
{
       cin>>n;
       dfs(0);
       return 0;
}

全排列的思想解决n皇后问题,用三个bool数组描述限制条件,用二维char数组保存结果,在恢复现场的时候也要恢复g数组,因为后面的其他结果可能不会将其覆盖掉。

#include<bits/stdc++.h>
//843 n皇后问题(全排列问题)
using namespace std;
const int N=20;
int path[N];//记录走过的路径
char g[N][N];
bool col[N],row[N],dg[N],udg[N];
int n;
void dfs(int u)
{
    //先判断是否已经得到一个答案
    if(u==n)
    {
        for(int i=0;i<n;i++)puts(g[i]);
        puts("");
        return;
    }
    for(int i=0;i<n;i++)
    {
       if(!col[i]&&!dg[u+i]&&!udg[n-u+i])
       {
           g[u][i]='Q';
           col[i]=dg[u+i]=udg[n-u+i]=true;
           dfs(u+1);
           col[i]=dg[u+i]=udg[n-u+i]=false;
           g[u][i]='.';
       }
    }
}
int main()
{
       cin>>n;
       for(int i=0;i<n;i++)
          for(int j=0;j<n;j++)
             g[i][j]='.';

       dfs(0);
       return 0;
}

 按照元素枚举的方式解决n皇后问题

#include<bits/stdc++.h>
//843 n皇后问题(全排列问题)
using namespace std;
const int N=20;
int path[N];//记录走过的路径
char g[N][N];
bool col[N],row[N],dg[N],udg[N];
int n;
void dfs(int x,int y,int u)//x为行,y为列
{
    if(y==n)y=0,x++;
    if(x==n)
    {
        if(u==n)//有可能到头了也没有找到全部的皇后
        {
            for(int i=0; i<n; i++)puts(g[i]);
            puts("");
        }
        return;
    }

    //为什么要添加xy两个参数
    //因为这个思路不是循环式地剪枝,是利用递归进行搜索
    //处理坐标

    //不放当前位置
    dfs(x,y+1,u);
    //放当前位置
    if(!row[x]&&!col[y]&&!dg[x+y]&&!udg[n-y+x])
    {
        g[x][y]='Q';
        row[x]=col[y]=dg[x+y]=udg[n-y+x]=true;
        dfs(x,y+1,u+1);
        g[x][y]='.';
        row[x]=col[y]=dg[x+y]=udg[n-y+x]=false;
    }


}
int main()
{
    cin>>n;
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            g[i][j]='.';
    dfs(0,0,0);
    return 0;
}

二、BFS

一层一层地搜索,如果边都是1,bfs第一次搜到的点具有最短路性质

搜索与图论(一)(深搜,广搜,树与图的存储遍历,拓扑排序),蓝桥准备,图论,深度优先,算法

1、具有最短路性质的原因:因为bfs每次都向外扩展一层,依次找到距离起点为1,2,3的所有点。

#include<bits/stdc++.h>
//844走迷宫//添加路径
using namespace std;
const int N=110;
typedef pair<int,int>PII;
int g[N][N];//存图
int d[N][N];//存距离
PII q[N*N];//模拟队列
PII pre[N][N];//路径的前驱
//由于最短路性质,可以直接将当前节点前的一个结点作为前驱
int n,m;

void bfs()
{
    memset(d,-1,sizeof d);//用于判断是否是第一次访问到
    //一个点可以有多个路径到达,但是第一个到达的一定是最短路
    d[0][0]=0;
    int hh=0,tt=0;
    q[0]={0,0};
    int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};
    while(hh<=tt)//只要非空
    {
       auto t=q[hh++];
       for(int i=0;i<4;i++)
       {
           int x=t.first+dx[i],y=t.second+dy[i];
           if(x>=0&&x<n&&y>=0&&y<m&&g[x][y]==0&&d[x][y]==-1)
           {
               d[x][y]=d[t.first][t.second]+1;
               q[++tt]={x,y};
               pre[x][y]=t;
           }
       }
    }
    int x=n-1,y=m-1;
    while(x||y)
    {
        cout<<x<<" "<<y<<endl;
        x=pre[x][y].first;
        y=pre[x][y].second;
    }
}

int main()
{
    cin>>n>>m;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            cin>>g[i][j];
    bfs();
    cout<<d[n-1][m-1];
    return 0;
}

三、邻接表邻接矩阵存图

1、邻接表的存法

搜索与图论(一)(深搜,广搜,树与图的存储遍历,拓扑排序),蓝桥准备,图论,深度优先,算法

2、使用h数组作为槽,利用e和ne数组和idx构造单链表存槽中相应结点有边相连的节点、

根据题意利用从1深搜,每一层用res存最大的子图的点数,每次计算出一个子连通图添加到sum中。

#include<bits/stdc++.h>
//846 树重心
using namespace std;
const int N=1e5+10,M=N*2;
typedef pair<int,int>PII;
int h[N],e[M],ne[M],idx;
bool st[N];
//h保存n个头结点
//在用数组模拟链表时,e保存链表结点值,ne保存边
//idx让这一切有序
int ans=N,n;//存结果
int dfs(int u)//u是结点的名字不是idx性质的
{
    st[u]=true;//标记这个结点已经被搜索过了
    //在遍历当前节点的所有子树之前
    int sum=1;//存所有子树的节点个数
    int res=0;//记录各个连通子图的节点个数
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j =e[i];
        if(st[j]==false)//只要这个结点的子树还没计算
        {
            int t=dfs(j);
            res=max(res,t);//存最大连通子图
            sum+=t;//所有子树
        }
    }
    res=max(res,n-sum);
    ans=min(ans,res);//保存最小的最大连通子图

    return sum;

}

void add(int a,int b)//头插法
{
  e[idx]=b;//每个idx都代表一个链表上的节点
  ne[idx]=h[a];
  h[a]=idx++;
}

int main()
{
    memset(h,-1,sizeof h);
    //memset(st,false,sizeof st);
    //所有结点的单链表指向的位置都为空
    cin>>n;
    for(int i=0;i<n-1;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    dfs(1);
    cout<<ans<<endl;

}

3、邻接表利用bfs计算最短路

#include<bits/stdc++.h>
//847图中点的层次
using namespace std;
const int N=1e5+10,M=2*N;
int n,m;
int h[N],e[N],ne[N],idx;
int d[N],q[N];
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int bfs()
{
    int hh=0,tt=0;
    memset(d,-1,sizeof d);
    q[0]=1;//1是结点的名字,入队
    d[1]=0;//到第一个结点的距离为0
    //数组模拟队列的时候hh永远指向队列的第一个元素,tt永远指向队尾,所以判断队列不为空的判断条件是hh<=tt。

    while(hh<=tt)
    {
      int t=q[hh++];//拿出队头元素
      for(int i=h[t];i!=-1;i=ne[i])//遍历与其相连的所有边
      {
          int j=e[i];//
          if(d[j]==-1)
          {
             d[j]=d[t]+1;
             q[++tt]=j;
          }

      }
    }
    return d[n];
}
int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof h);
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
    }
    cout<<bfs()<<endl;
    return 0;
}

4、有向无环图一定有拓扑序列,拓扑排序的实现文章来源地址https://www.toymoban.com/news/detail-827329.html

#include<bits/stdc++.h>
//848拓扑排序
using namespace std;
const int N=1e5+10,M=2*N;
int n,m;
int h[N],e[N],ne[N],idx;
int d[N],q[N];

void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

bool topsort()
{
    int hh=0,tt=-1;
    for(int i=1;i<=n;i++)
    {
        if(!d[i])q[++tt]=i;
    }
    while(hh<=tt)
    {
        int t=q[hh++];
        for(int i=h[t];i!=-1;i=ne[i])
        {
           int j=e[i];
           d[j]--;
           if(!d[j])q[++tt]=j;

        }
    }
    return tt==n-1;
}

int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof h);
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
        d[b]++;
    }
    if(!topsort())puts("-1");
    else
    {
        for(int i=0;i<n;i++)cout<<q[i]<<" ";
        puts("");

    }
}

到了这里,关于搜索与图论(一)(深搜,广搜,树与图的存储遍历,拓扑排序)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 深度优先搜索(DFS、深搜)和广度优先搜索(BFS、广搜)

    目录 深度优先搜索(DFS、深搜)和广度优先搜索(BFS、广搜) 深度优先搜索(简称“深搜”或DFS) 广度优先搜索 总结 深度优先生成树和广度优先生成树 非连通图的生成森林 深度优先生成森林 广度优先生成森林 图 1 无向图 深度优先搜索的过程类似于树 的先序遍历 ,首先

    2024年01月20日
    浏览(40)
  • 图论第二天|岛屿数量.深搜版、岛屿数量.广搜版、岛屿的最大面积、1020.飞地的数量

    文档讲解 :代码随想录 - 岛屿数量.深搜版 状态:开始学习。 本题是dfs模板题 本题代码: 文档讲解 :代码随想录 - 岛屿数量.广搜版 状态:开始学习。 思路:bfs模板题 本题代码: 文档讲解 :代码随想录 - 岛屿的最大面积 状态:开始学习。 思路: 这道题目也是 dfs bfs 基础

    2024年02月08日
    浏览(27)
  • 【图论】图的存储--链式前向星存图法以及深度优先遍历图

    无向图 - 就是一种特殊的有向图 - 只用考虑有向图的存储即可 邻接矩阵 邻接表 邻接表 存储结构: (为每一个点开了一个单链表,存储这个点可以到达哪个点) 1 : 3-4-null 2 : 1-4-null 3 : 4-null 4 : null 插入一条新的边 比如要插一条边: 2-3 先找到 2 对应的 单链表 然后将 3 插入到单链表

    2024年04月14日
    浏览(34)
  • 学习高级数据结构:探索平衡树与图的高级算法

    🎉欢迎来到数据结构学习专栏~学习高级数据结构:探索平衡树与图的高级算法 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:数据结构学习 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技

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

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

    2023年04月08日
    浏览(69)
  • 【算法】复习搜索与图论

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

    2024年02月05日
    浏览(39)
  • 搜索与图论:Prim

    每次将离连通部分的最近的点和点对应的边加入的连通部分,连通部分逐渐扩大,最后将整个图连通起来,并且边长之和最小。

    2024年02月08日
    浏览(29)
  • 搜索与图论-拓扑序列

    为什么记录呢 因为不记录全忘了 虽然记了也不一定会看 有向无环图一定有拓扑序列 邮箱无环图 - 拓扑图 入度为0的点作为起点 入度为0的点入队列 枚举出边 t-j 删掉当前边,t-j . j的入度减1 判断j的入度是否为0,来判断是否加入队列 有环: 不存在入度为0的点

    2024年02月11日
    浏览(30)
  • 搜索与图论(三)

    朴素版Prim 一般用于稠密图 算法流程: 集合表示当前已经在连通块的点 1.初始化距离,把所有距离都初始化为正无穷 2.n次迭代,找到集合外距离最小的点 -t 3.用t来更新其它点到集合的距离 一般用于稀疏图 算法流程: 1.将所有边按照权重从小到大排序 2.枚举每一条边(a,b),权重为

    2024年02月14日
    浏览(24)
  • 搜索与图论(二)

    所有边权都是正数 朴素Dijkstra算法 基本思路: 从1号点到其他点的最短距离 步骤: 定义一个s集合包含当前已确定最短距离的点 1、初始化距离dis[1] = 0,dis[其它] = 正无穷 2、for i 0-n循环n次      2.1找到不在s中的距离最近的点 -t     2.2把t加到s当中去     2.3用t来更新其它点的距

    2024年02月14日
    浏览(25)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包