实验08 图遍历与存储结构

本文通过五个实战案例介绍图的邻接矩阵存储、邻接表构建、深度优先与广度优先搜索算法,以及计算由1围成图形的面积。涵盖图的基本操作和高级应用。

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

A. DS图—图的邻接矩阵存储及度计算

题目描述

假设图用邻接矩阵存储。输入图的顶点信息和边信息,完成邻接矩阵的设置,并计算各顶点的入度、出度和度,并输出图中的孤立点(度为0的顶点)

–程序要求–
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求

输入

测试次数T,每组测试数据格式如下:

图类型 顶点数 (D—有向图,U—无向图)

顶点信息

边数

每行一条边(顶点1 顶点2)或弧(弧尾 弧头)信息

输出

每组测试数据输出如下信息(具体输出格式见样例):

图的邻接矩阵

按顶点信息输出各顶点的度(无向图)或各顶点的出度 入度 度(有向图)。孤立点的度信息不输出。

图的孤立点。若没有孤立点,不输出任何信息。

输入样例1

2
D 5
V1 V2 V3 V4 V5
7
V1 V2
V1 V4
V2 V3
V3 V1
V3 V5
V4 V3
V4 V5
U 5
A B C D E
5
A B
A C
B D
D C
A D

输出样例1

0 1 0 1 0
0 0 1 0 0
1 0 0 0 1
0 0 1 0 1
0 0 0 0 0
V1: 2 1 3
V2: 1 1 2
V3: 2 2 4
V4: 2 1 3
V5: 0 2 2
0 1 1 1 0
1 0 0 1 0
1 0 0 1 0
1 1 1 0 0
0 0 0 0 0
A: 3
B: 2
C: 2
D: 3
E

代码

#include<iostream>

using namespace std;
int num;
int found(string a,string *s){
    int i;
    for(i=0;i<num;i++){
        if(a==s[i]) return i;
    }
}
int main() {
    int T, i, bian,j;
    char ch;
    cin >> T;
    while (T--) {
        int juzhen[100][100]={0};
        cin >> ch >> num;
        string s1,s2;
        int k1,k2;
        if (ch == 'D') {
            int chu[100]={0};
            int ru[100]={0};

            string * str = new string[num];
            for (i = 0; i < num; i++)
                cin >> str[i];
//            cout<<str->size();
            cin >> bian;
            for(i=0;i<bian;i++){
                cin>>s1>>s2;
                k1= found(s1,str);
                chu[k1]++;

                k2= found(s2,str);

                ru[k2]++;
                juzhen[k1][k2]=1;
            }
            for(i=0;i<num;i++){
                for( j=0;j<num;j++){
                    if(j<num-1) cout<<juzhen[i][j]<<' ';
                    else cout<<juzhen[i][j]<<endl;
                }
            }
            string wu[100];
            int wwu=0;
            for(i=0;i<num;i++){
                if(chu[i]+ru[i]!=0){
                    cout<<str[i]<<": ";
                    cout<<chu[i]<<' '<<ru[i]<<' '<<chu[i]+ru[i]<<endl;
                }
                else {
                    wu[wwu++]=str[i];
                }
            }
            if(wwu){
                for(i=0;i<wwu;i++)
                    cout<<wu[i]<<endl;
            }
        } else if (ch == 'U') {
            int du[100]={0};
            string * str = new string[num];
            for (i = 0; i < num; i++)
                cin >> str[i];

            cin >> bian;
            for(i=0;i<bian;i++){
                cin>>s1>>s2;
                k1= found(s1,str);
                du[k1]++;
                k2= found(s2,str);
                du[k2]++;
                juzhen[k1][k2]=1;
                juzhen[k2][k1]=1;
            }
            for(i=0;i<num;i++){
                for( j=0;j<num;j++){
                    if(j<num-1) cout<<juzhen[i][j]<<' ';
                    else cout<<juzhen[i][j]<<endl;
                }
            }
            string wu[100];
            int wwu=0;
            for(i=0;i<num;i++){
                if(du[i]!=0){
                    cout<<str[i]<<": ";
                    cout<<du[i]<<endl;
                }
                else {
                    wu[wwu++]=str[i];
                }
            }
            if(wwu){
                for(i=0;i<wwu;i++)
                    cout<<wu[i]<<endl;
            }
        }
    }
    return 0;
}

B. 图综合练习–构建邻接表

题目描述

已知一有向图,构建该图对应的邻接表。

邻接表包含数组和单链表两种数据结构,其中每个数组元素也是单链表的头结点,数组元素包含两个属性,属性一是顶点编号info,属性二是指针域next指向与它相连的顶点信息。

单链表的每个结点也包含两个属性,属性一是顶点在数组的位置下标,属性二是指针域next指向下一个结点。

输入

第1行输入整数t,表示有t个图

第2行输入n和k,表示该图有n个顶点和k条弧。

第3行输入n个顶点。

第4行起输入k条弧的起点和终点,连续输入k行

以此类推输入下一个图

输出

输出每个图的邻接表,每行输出格式:数组下标 顶点编号-连接顶点下标-…-^,数组下标从0开始。

具体格式请参考样例数据,每行最后加入“^”表示NULL。

输入样例1

1
5 7
A B C D E
A B
A D
A E
B D
C B
C E
E D

输出

0 A-1-3-4-^
1 B-3-^
2 C-1-4-^
3 D-^
4 E-3-^

代码

#include<iostream>
int n;
using namespace std;
int found(char a,char s[100][100]){
    int i;
    for(i=0;i<n;i++){
        if(a==s[i][0]) return i;
    }
}
int main(){
    int t,k,i;
    cin>>t;
    while(t--){
        cin>>n>>k;
        char ch1,ch2;
        char da[100][100];
        int k1,k2;
        int num[100]={0};
        for(i=0;i<n;i++)
            cin>>da[i][0];
        for(i=0;i<k;i++)
        {
            cin>>ch1>>ch2;
            k1= found(ch1,da);
            k2= found(ch2,da);
            da[k1][num[k1]+1]=k2+'0';
            num[k1]++;
        }

        for(i=0;i<n;i++){
            cout<<i<<' '<<da[i][0];
            for(int j=1;j<=num[i];j++)
                cout<<'-'<<da[i][j];
            cout<<"-^\n";
        }
    }
}

C. DS图遍历–深度优先搜索

题目描述

给出一个图的邻接矩阵,对图进行深度优先搜索,从顶点0开始

以下代码框架仅供参考,同学们可在理解的基础上自行设计算法,不强制要求和框架相同

注意:图n个顶点编号从0到n-1

代码框架如下:

在这里插入图片描述
在这里插入图片描述

输入

第一行输入t,表示有t个测试实例

第二行输入n,表示第1个图有n个结点

第三行起,每行输入邻接矩阵的一行,以此类推输入n行

第i个结点与其他结点如果相连则为1,无连接则为0,数据之间用空格隔开

以此类推输入下一个示例

输出

每行输出一个图的深度优先搜索结果,结点编号之间用空格隔开

输入样例1

2
4
0 0 1 1
0 0 1 1
1 1 0 1
1 1 1 0
5
0 0 0 1 1
0 0 1 0 0
0 1 0 1 1
1 0 1 0 0
1 0 1 0 0

输出

0 2 1 3
0 3 2 1 4

代码

#include<iostream>
using namespace std;
const int MaxLen=20;
int n;
int da[20][20]={0};
class Map{
private:
    bool Visit[MaxLen];
    int Matrix[MaxLen][MaxLen];
    int Vexnum;
    void DFS(int v);

public:
    void SetMatrix(int vnum,int mx[MaxLen][MaxLen]);
    void DFSTraverse();
};

void Map::SetMatrix(int vnum, int (*mx)[20]) {
    int i,j;
    Vexnum=vnum;
    for(i=0;i<MaxLen;i++)
        for(j=0;j<MaxLen;j++)
            Matrix[i][j]=0;

        for(i=0;i<Vexnum;i++)
            for(j=0;j<Vexnum;j++)
                Matrix[i][j]=mx[i][j];
}

void Map::DFSTraverse() {
    int i;
    for(i=0;i<Vexnum;i++)
         Visit[i]=false;
    for(i=0;i<Vexnum;i++)
        if(!Visit[i]) DFS(i);
    cout<<endl;
}

void Map::DFS(int v) {
    int w,i,k;
    Visit[v]= true;
    cout<<v<<' ';

    int *AdjVex=new int [Vexnum];
    for(i=0;i<Vexnum;i++)
        AdjVex[i]=-1;
    k=0;
    for(i=0;i<Vexnum;i++){
        if(Matrix[v][i]==1) AdjVex[k++]=i;
    }
    i=0;
    for(w=AdjVex[i];w!=-1;w=AdjVex[++i]){
        if(!Visit[w]) DFS(w);
     }
    delete []AdjVex;
}

int main(){
    int t,i,j;
    cin>>t;
    while(t--){
        cin>>n;
        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
                cin>>da[i][j];
        Map p;
        p.SetMatrix(n,da);
        p.DFSTraverse();
    }
}

D. DS图遍历–广度优先搜索

题目描述

给出一个图的邻接矩阵,对图进行深度优先搜索,从顶点0开始

以下代码框架仅供参考,同学们可在理解的基础上自行设计算法,不强制要求和框架相同

注意:图n个顶点编号从0到n-1

代码框架如下:

在这里插入图片描述

输入

第一行输入t,表示有t个测试实例

第二行输入n,表示第1个图有n个结点

第三行起,每行输入邻接矩阵的一行,以此类推输入n行

第i个结点与其他结点如果相连则为1,无连接则为0,数据之间用空格隔开

以此类推输入下一个示例

输出

每行输出一个图的广度优先搜索结果,结点编号之间用空格隔开

输入样例1

2
4
0 0 1 1
0 0 1 1
1 1 0 1
1 1 1 0
5
0 0 0 1 1
0 0 1 0 0
0 1 0 1 1
1 0 1 0 0
1 0 1 0 0

输出

0 2 3 1
0 3 4 2 1

代码

#include<bits/stdc++.h>

using namespace std;
const int MaxLen = 20;
int n;
int da[20][20] = {0};

class Map {
private:
    bool Visit[MaxLen];
    int Matrix[MaxLen][MaxLen];
    int Vexnum;

    void BFS(int v);

public:
    void SetMatrix(int vnum, int mx[MaxLen][MaxLen]);

    void BFSTraverse();
};

void Map::SetMatrix(int vnum, int (*mx)[20]) {
    int i, j;
    Vexnum = vnum;
    for (i = 0; i < MaxLen; i++)
        for (j = 0; j < MaxLen; j++)
            Matrix[i][j] = 0;

    for (i = 0; i < Vexnum; i++)
        for (j = 0; j < Vexnum; j++)
            Matrix[i][j] = mx[i][j];
}

void Map::BFSTraverse() {
    BFS(0);
}

void Map::BFS(int v) {
    int w, u;
    int i, k;
    int *AdjVex = new int[Vexnum];
    for (i = 0; i < Vexnum; i++)
        AdjVex[i] = -1;
    queue<int> Q;
    for (i = 0; i < Vexnum; i++)
        Visit[i] = false;

    for (v = 0; v < Vexnum; v++) {
        if (!Visit[v]) {
            Visit[v] = true;
            cout << v << ' ';
            Q.push(v);
            while (!Q.empty()) {
                u = Q.front();
                Q.pop();
                k = 0;
                for (i = 0; i < Vexnum; i++) {
                    if (Matrix[u][i] == 1) AdjVex[k++] = i;
                }

                i = 0;
                for (w = AdjVex[i]; w >= 0; w = AdjVex[++i]) {
                    if (!Visit[w]) {
                        Visit[w] = true;
                        cout << w << ' ';
                        Q.push(w);
                    }
                }
            }
        }
    }
    cout << endl;
}

int main() {
    int t, i, j;
    cin >> t;
    while (t--) {
        cin >> n;
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++)
                cin >> da[i][j];
        Map p;
        p.SetMatrix(n, da);
        p.BFSTraverse();
    }
}

E. DS图—图非0面积

题目描述

编程计算由"1"围成的下列图形的面积。面积计算方法是统计"1"所围成的闭合曲线中"0"点的数目。如图所示,在10*10的二维数组中,"1"围住了15个点,因此面积为15。

提示:queue

输入

测试次数t

每组测试数据格式为:

数组大小m,n

一个由0和1组成的m*n的二维数组

输出

对每个二维数组,输出符号"1"围住的"0"的个数,即围成的面积。假设一定有1组成的闭合曲线,但不唯一。

输入样例1

2
10 10
0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 0 0 0
0 0 0 0 1 0 0 1 0 0
0 0 0 0 0 1 0 0 1 0
0 0 1 0 0 0 1 0 1 0
0 1 0 1 0 1 0 0 1 0
0 1 0 0 1 1 0 1 1 0
0 0 1 0 0 0 0 1 0 0
0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0
5 8
0 1 1 0 0 1 1 0
1 0 1 0 1 0 0 1
0 1 0 1 0 0 1 0
0 1 0 0 1 1 1 0
0 0 0 0 0 0 0 0

输出

15
5

代码

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

class Map
{
public:
    int graph[100][100];
    int m,n;
    void initialize()
    {
        for(int i=0;i<=m+1;i++)//先将二维数组初始化为0
            for(int j=0;j<=n+1;j++)
                graph[i][j]=0;
        cin >> m >> n;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
                cin >> graph[i][j];
    }
    void BFS()
    {
        int x=0,y=0;
        queue<int> Qx,Qy;
        Qx.push(x);
        Qy.push(y);
        graph[x][y]=1;
        int nx[4]={-1,0,1,0};//在for循环中分别对应上下左右的结点
        int ny[4]={0,1,0,-1};
        while(!Qx.empty()){
            for(int i=0;i<4;i++){//判断上下左右的结点是否合格
                if(Qx.front()+nx[i]>=0&&Qx.front()+nx[i]<=m+1&&Qy.front()+ny[i]>=0&&Qy.front()+ny[i]<=n+1&&graph[Qx.front()+nx[i]][Qy.front()+ny[i]]==0){
                    Qx.push(Qx.front()+nx[i]);
                    Qy.push(Qy.front()+ny[i]);
                    graph[Qx.front()+nx[i]][Qy.front()+ny[i]]=1;//合格就变成墙
                }
            }
            Qx.pop();
            Qy.pop();
        }

    }
    void print()
    {
        int num=0;
        for(int i=0;i<=m;i++)
            for(int j=0;j<=n;j++)
                if(graph[i][j]==0)num++;
        cout<<num<<endl;
    }
    
};

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        Map mygraph;
        mygraph.initialize();
        mygraph.BFS();
        mygraph.print();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值