题目:

7-1 列出连通集 (30 分)

给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。

输入格式:

输入第1行给出2个整数N(0<N10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。

输出格式:

按照 “ { v1, v2, v3, ... ,vk } ”的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。

1​​ v2​​ ... vk​​ }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。

输入样例:

8 6
0 7
0 1
2 0
4 1
2 4
3 5

输出样例:

{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }

 

分析:

 当读完这道题之后,很容易就能够知道我们需要做的两件事:①构建图  ②DFS遍历和BFS遍历

这里为了方便起见(同时数据量并不大),这里将采用邻接矩阵存储图。

 


代码:

对结构体结构的定义:

#define max 10
typedef int vertex_type;
typedef int edge_type;
typedef struct graph_matrix{
    int n, e;//顶点数;边数 
    vertex_type vexs[max];//顶点一维数组 
    edge_type edges[max][max];//邻接矩阵二维数组,元素类型为vector<vertex_type>
}gm;

 

全局变量visit[]

//visit[]数组;全局变量 
int visit[max] = {0};

 

①构建图

//创建图 
void create_gm(gm &gm)
{ 
    cin>>gm.n>>gm.e;
    memset(gm.edges, 0, sizeof(gm.edges));
    for(int i=0; i<gm.n; i++){
        gm.vexs[i] = i;
    }
    
    //输入边数据 
    int a, b;
    for(int i=0; i<gm.e; i++){
        cin>>a>>b;
        gm.edges[a][b] = 1;
        gm.edges[b][a] = 1;
    }
}

 

②DFS遍历

//深度优先 
//id: 以id为起始点
void DFS(gm &gm, int id)
{
    visit[id] = 1;
    cout<<id<<" ";
    for(int i=0; i<gm.n; i++){
        if(gm.edges[i][id] == 1 && visit[i] == 0){
            DFS(gm, i);
        }
    }
 } 

 

③BFS遍历

//宽度优先 
 void BFS(gm &gm, int id)
{
    visit[id] = 1;
    queue<int> qu; 
    qu.push(id);
    while(qu.size() != 0){
        int mark = qu.front();
        qu.pop();
        cout<<mark<<" ";
        for(int i=0; i<gm.n; i++){
            if(gm.edges[i][mark] == 1 && visit[i] == 0){
                visit[i] = 1;
                qu.push(i);
            }
        }
    }
 }

 

全部的代码:

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

#define max 10
typedef int vertex_type;
typedef int edge_type;
typedef struct graph_matrix{
    int n, e;//顶点数;边数 
    vertex_type vexs[max];//顶点一维数组 
    edge_type edges[max][max];//邻接矩阵二维数组,元素类型为vector<vertex_type>
}gm;

//函数声明 
void create_gm(gm &gm);  
void DFS(gm &gm, int id);
void BFS(gm &gm, int id);

//visit[]数组;全局变量 
int visit[max] = {0};

int main()
{
    gm gm;//定义一个叫做gm的邻接矩阵 
    create_gm(gm);
    
    //调用DFS遍历 
    for(int i=0; i<gm.n; i++){
        if(visit[i] == 1)continue;
        cout<<"{ ";
        DFS(gm ,i);
        cout<<"}"<<endl;
    }
    
    //重置visit[]数组 
    memset(visit, 0, sizeof(visit));
    
    //调用BFS遍历 
    for(int i=0; i<gm.n; i++){
        if(visit[i] == 0){
            cout<<"{ ";
            BFS(gm ,i);
            cout<<"}"<<endl;
        }
    }
    return 0;
 } 
 
//创建图 
void create_gm(gm &gm)
{ 
    cin>>gm.n>>gm.e;
    memset(gm.edges, 0, sizeof(gm.edges));
    for(int i=0; i<gm.n; i++){
        gm.vexs[i] = i;
    }
    
    //输入边数据 
    int a, b;
    for(int i=0; i<gm.e; i++){
        cin>>a>>b;
        gm.edges[a][b] = 1;
        gm.edges[b][a] = 1;
    }
}

//深度优先 
void DFS(gm &gm, int id)
{
    visit[id] = 1;
    cout<<id<<" ";
    for(int i=0; i<gm.n; i++){
        if(gm.edges[i][id] == 1 && visit[i] == 0){
            DFS(gm, i);
        }
    }
 } 
 
//宽度优先 
 void BFS(gm &gm, int id)
{
    visit[id] = 1;
    queue<int> qu; 
    qu.push(id);
    while(qu.size() != 0){
        int mark = qu.front();
        qu.pop();
        cout<<mark<<" ";
        for(int i=0; i<gm.n; i++){
            if(gm.edges[i][mark] == 1 && visit[i] == 0){
                visit[i] = 1;
                qu.push(i);
            }
        }
    }
 }
ALL

 


总结:

 在这个题目中主要是对之前在树章节中,对关于树的前序遍历(DFS)和层次遍历(BFS)的知识迁移。

 

① DFS往往会运用到来进行实现,而递归就是利用栈的一个实现方法,递归特性使算法代码简洁的同时,也使算法理解困难,

所以对于我这种初学者来说画图和动手实践是最好的学习方法。

例子:“走迷宫,你没有办法用分身术同时走进多叉道路中,不撞南墙不回头。”(来源自网络)

 

② BFS则是要运用到队列,程序流程相对于DFS来说更为清晰。

例子:“当你眼镜掉了,你趴在地上找,你总是会先摸靠近你的地方,如果没有,再摸远一点的地方。”(来源自网络)

 

如何对已有知识的新运用也是能力提升的一种,在此我也对DFS和BFS有了更深一层的理解。

嘻嘻:)

 

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!