基于dfs深度优先搜索的破圈法最短路径

本文介绍了管梅谷教授提出的破圈算法,用于找到无向图的最小生成树。基本思路包括寻圈和寻边,通过不断删除回路中最大权重的边来构建生成树。文章详细阐述了算法的步骤,包括深搜查圈、最大值破圈和重新深搜查圈,并展示了程序框图。最后,提供了C++代码实现,并给出了运行截图以验证算法的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

破圈法定义

破圈算法是1975年由我国数学家管梅谷教授提出来的。其基本思想是在给定的图中任意找出一个环路,删去该环路中权最大的边,然后在余下的图中再任意找出一个回路,再删去这个新找出的回路中权最大的边,……,一直重复上述过程,直到剩余的图中没有回路。剩余图便是最小生成树。

基本思路

破圈,顾名思义就是找到圈然后破开,直到整个图没有圈就是生成树,破圈法的主要注意事项有两个

寻圈

寻找回路是破圈法的基础,在生成生成树的过程中,用到破圈法时需要先找到回路,然后将回路断开,不断地对图的每一个点进行操作,直至整个图没有回路,这个图就变成了一个生成树

寻边

寻边就是指在破圈的过程中,对每一个寻圈寻找到的回路的边搜索最大值,当破圈行为发生时,直接破除最大值的边

循环

当对某个点,不断地进行寻边,破圈,需要对这个图进行及时的更新,当破圈的事件发生的时候,下一次寻边,需要在上一次破圈行为发生的基础上进行,也就是说,破圈之后要对原图及时更新

程序框图

这里按照如下的图为例

1
20
6
4
7
9
2
100
1
2
3
4
5

由于是无向图,不难看出上图是错误的(因为懒得删除了),我们看下面的图片

在这里插入图片描述

不难看出这个图有很多的回路,如下是其临界矩阵的表达方式

邻接矩阵12345
1012000
210647
3206092
40490100
50721000

操作步骤

深搜查圈

我们把起始点设置为第一个点,把顺序按照1 2 3 4 5深 的顺序进行搜索,对于每一次搜索,当经过某个点并且这个点不是起始点的时候,就把他进行标记,防止重复搜索,当搜索有发生到起始点的时候,证明深搜搜索到了回路,其s深搜演示图如下图所示ter)显然,第四次s搜的过程中,以一个点就搜索到了起始点1,代表着此图搜索到了回路,搜索过程如下图所示:

搜索过程
在这里插入图片描述

最大值破圈

对于搜索到的第一个圈而言,我们需要找到权重最大的边进行破圈,并且更新无向图,这样才能使下面的广搜不受影响

很明显,第一次深搜就搜索到了回路,接下来执行破圈,在搜索的过程中记录权重最大的边的坐标,然后将其删除,删除之后的无向图如下所示
在这里插入图片描述

重新深搜查圈

对于节点gen,当其上一次查圈成功并且破圈之后,在上一圈的基础上重新对该节点进行查圈破圈操作,重复上述操作,既可以得到最小生成树

再上图更新权重的基础上,以节点1重新进行搜索,很明显并没有回路,程序跳转,对下一个节点(也就是二进行深搜)

不停的重复上诉操作三个,由默认顺序可以得到,如果代码正确,其破圈顺序应该如下所示
在这里插入图片描述

基本变量与函数传参

基本变量

下面进行对变量的阐明

#define MIN 0 代表着不可达或者无路
int find_x; int find_y; 最大值的坐标
int drive[6][6]={0}; 代表邻接矩阵
int getd[6]={0}; 代表着点是否被访问到,其中1代表已经访问,0代表尚未访问 注:对于根节点而言他总是被访问到的

函数传参

void initial_getd() 初始化点达到数组为未达到
void create ( ) 初始化邻接矩阵
void bfs_search(int first,int tempf,int gen,int tempx,int tempy) 广搜代码,其中

参数意义
first代表着当前节点
tempf代表着上一个节点
gen代表着根节点
tempx用于调试的x坐标代码,无实际意义
tempy用于调试的y坐标代码,无实际意义

如上是代码的核心算法

全部代码

下面展示全部代码(对于某些部位附上注释)

#include<bits/stdc++.h>
using namespace std;
#define MAX 114514 
#define MIN 0         //代表不可达
bool find;
int  find_x;
int find_y;
int find_temp_x;
int find_temp_y;
int drive[6][6]={0};
int getd[6]={0};
void initial_getd()
{
    for(int i=1;i<=5;i++)
    {
        getd[i]=0;
    }
}
void create ()
{
    int temp;
    cin>>temp;
    for(int i=0;i<temp;i++)
    {
        int j,k;
        cin>>j>>k;
        cin>>drive[j][k];
        drive[k][j]=drive[j][k];
    }
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=5;j++)
        {
            cout<<"  "<<drive[i][j];
        }
        cout<<endl;
    }
}

void dfs_search(int first,int tempf,int gen,int tempx,int tempy)
{
  
    int right_point=gen;  
    getd[gen]=1;
    for(int j=1;j<=5;j++)
    {
        if(drive[first][j]!=0&&j==gen&&j!=tempf&&first!=j)//找到根节点
        { 
            if(drive[first][j]>=drive[find_x][find_y])
            {
                find_x=first;
                find_y=j;
            }        
            if(j==gen) //当搜到结点的时候,相当于找到回路,进行破圈操作
            {   
                cout<<endl;
                drive[find_x][find_y]=0;
                drive[find_y][find_x]=0;
                for(int i=1;i<=5;i++)
                {
                    for(int j=1;j<=5;j++)
                    {
                        cout<<"  "<<drive[i][j];
                    }
                    cout<<endl;
                }
                    cout<<endl;
                    initial_getd();
                    ddfs_search(right_point,right_point,right_point,right_point,right_point);//从新调用广搜
                    return ;//结束下列搜索
                    } 

                }
                if(drive[first][j]!=0&&getd[j]==0&&j!=tempf)//三个条件同时满足分别为 1.有路,2未达,3不是回到上一个节点
                {
                    if(drive[first][j]>=drive[find_x][find_y])//如果全重大就更新
                    { 
                        find_x=first;
                        find_y=j;
                    }
                    find_temp_x=first;
                    find_temp_y=j;
                    getd[j]=1;
                    getd[first]=1;
                    dfs_search(j,first,gen,find_temp_x,find_temp_y);//搜索下一个点
                    getd[j]=0;//初始化
                    if(first!=gen)//防止根节点被设为未达
                    getd[first]=0;
                }
        }
}






int main (void)
{
    create();
    for(int i=1;i<=5;i++)
    {
        cout<<getd[i]<<endl;
    }
    for(int i=1;i<=5;i++)
    {
        dfs_search(i,i,i,i,i);
        find_x=1;
        find_y=1;
    }
     for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=5;j++)
        {
            cout<<"  "<<drive[i][j];
        }
        cout<<endl;
    }
        cout<<endl<<endl;
        system("pause");
    
}
//测试案例
/*
8
1 2 1
1 3 20
2 3 6
2 4 4
2 5 7
3 5 2
3 4 9
4 5 100
*/

运行截图

在这里插入图片描述
结果正确!

总结

其实搜索过程也可以用广搜解决

如有错误,希望指正谢谢

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值