实验5:图

集美大学课程实验报告-实验5:图

项目名称 内容
课程名称 数据结构
班级 网安2411
指导教师 郑如滨
学生姓名 于鸿硕
学号 202421336018
实验项目名称 实验5:图
上机实践日期
上机实践时间 2学时


一、目的(本次实验所涉及并要求掌握的知识点)

  • 掌握图的基本操作方法 理解图的特性
    熟练掌握两种遍历方式 简单掌握图运用至实际情况中的方法

二、实验内容与设计思想

#include <iostream>
#include<cstring>
#include<vector>
#include<queue>

//图结构定义
const int MAX_VERTEX_NUM = 100;
struct MGraph {
	char vexs[MAX_VERTEX_NUM];
	int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
	int vexnum, arcnum;
};

using namespace std;
    return 0;

任务一、二:图的创建与遍历

//伪代码:
初始化图:
    定义图的邻接矩阵的行列长度;
    给邻接矩阵附值“A B C...”;
    初始化数组元素为0;
    在有值区域给邻接矩阵赋1;

输出图:
    嵌套循环
        输出0 1 值;

DFS:
    检验是否已遍历过;
    把图存入result中;
    嵌套循环遍历;
    
BFS:
    前序操作与DFS基本相同,区别点:
        起始顶点入队;标记已访问节点;
        当队列不为空时:
            获取队头值,队头出队;
        嵌套循环访问未访问节点:
            邻接节点入队;
    

//代码:
#include<iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

//图结构定义
const int MAX_VERTEX_NUM = 100;
struct MGraph {
	char vexs[MAX_VERTEX_NUM];
	int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
	int vexnum, arcnum;
};

//初始化图
void InitGraph(MGraph& G) {
	G.vexnum = 6;
	G.arcnum = 9;
	G.vexs[0] = 'A';
	G.vexs[1] = 'B';
	G.vexs[2] = 'C';
	G.vexs[3] = 'D';
	G.vexs[4] = 'E';
	G.vexs[5] = 'F';
	memset(G.arcs, 0, sizeof(G.arcs));
	G.arcs[0][1] = 1; G.arcs[1][0] = 1;
	G.arcs[0][4] = 1; G.arcs[4][0] = 1;
	G.arcs[1][4] = 1; G.arcs[4][1] = 1;
	G.arcs[1][5] = 1; G.arcs[5][1] = 1;
	G.arcs[2][3] = 1; G.arcs[3][2] = 1;
	G.arcs[2][5] = 1; G.arcs[5][2] = 1;
	G.arcs[3][5] = 1; G.arcs[5][3] = 1;
}

//输出图
void PrintGraph(const MGraph& G)
{
	for (int i = 0;i < G.vexnum;i++)
	{
		for (int j = 0;j < G.vexnum;j++)
		{
			cout << G.arcs[i][j] << " ";
		}
		cout << endl;
	}
}

//深度优先辅助函数
void DFS(const MGraph& G, int v, bool visited[], vector<char>& result)
{
	visited[v] = true;
	result.push_back(G.vexs[v]);
	for (int i = 0;i < G.vexnum;i++)
	{
		if (G.arcs[v][i] && !visited[i])
		{
			DFS(G, i, visited, result);
		}
	}
}
//深度优先函数
vector<char>DFSTranverse(const MGraph& G, char start)
{
	bool visited[MAX_VERTEX_NUM];
	memset(visited, false, sizeof(visited));
	vector<char> result;
	int startIndex = -1;
	for (int i = 0;i < G.vexnum;i++)
	{
		if (G.vexs[i] == start)
		{
			startIndex = i;
			break;
		}
	}
	if (startIndex != -1)DFS(G, startIndex, visited, result);
	return result;
}

//广度优先
vector<char> BFSTraverse(const MGraph& G, char start) {
	bool visited[MAX_VERTEX_NUM];
	memset(visited, false, sizeof(visited));
	vector<char> result;
	queue<int> q;
	int startIndex = -1;
	for (int i = 0; i < G.vexnum; ++i) {
		if (G.vexs[i] == start) {
			startIndex = i;
			break;
		}
	}
	if (startIndex != -1) {
		q.push(startIndex);
		visited[startIndex] = true;
		while (!q.empty()) {
			int v = q.front();
			q.pop();
			result.push_back(G.vexs[v]);
			for (int i = 0; i < G.vexnum; ++i) {
				if (G.arcs[v][i] && !visited[i]) {
					q.push(i);
					visited[i] = true;
				}
			}
		}
	}
	return result;
}

//主函数
int main() {
	MGraph G;
	InitGraph(G);
	cout << "图的邻接矩阵:" << endl;
	PrintGraph(G);

	vector<char>dfsResultA = DFSTranverse(G, 'A');
	cout << "自A进行DFS:";
	for (char c : dfsResultA) {
		cout << c;
	}
	cout << endl;

	vector<char>dfsResultF = DFSTranverse(G, 'F');
	cout << "自F进行DFS:";
	for (char c : dfsResultF) {
		cout << c;
	}
	cout << endl;

	vector<char>bfsResultF = BFSTraverse(G, 'F');
	cout << "自F进行BFS:";
	for (char c : bfsResultF)
	{
		cout << c;
	}
	cout << endl;

	return 0;
}

任务三:图着色问题

//伪代码:
主函数:
    输入vek;输入uv并存入边集;
    输入N;
    对N个方案for循环:
        输入颜色,插入颜色集;
    如果颜色树!=K 则false;
    else  提取边集
          if(边集颜色==)false并break;
    cout<<判断True or false<<yes or no;

//代码:
#include<iostream>
#include<vector>
#include<set>
using namespace std;

int main()
{
    int V,E,K;
    cin>>V>>E>>K;

    vector<pair<int,int>> edges;
    for(int i=0;i<E;i++){
        int u,v;
        cin>>u>>v;
        edges.emplace_back(u,v);
    }

    int N;
    cin>>N;

    for(int i=0;i<N;i++){
        vector<int> colors(V+1);
        bool valid=true;
        set<int> usedColors;

        for(int j=1;j<=V;j++){
            cin>>colors[j];
            usedColors.insert(colors[j]);
        }

        if(usedColors.size()!=K)valid=false;
        else{
            for(const auto& edge:edges)
            {
                int u=edge.first;
                int v=edge.second;
                if(colors[u]==colors[v])
                {
                    valid=false;
                    break;
                }
            }
        }
        cout<<(valid ? "Yes":"No")<<endl;
    }
    return 0;
}

任务四:公路村村通

//伪代码:
1.设计两个查验函数,分别用于检查两个城镇是否已连接和按路径权重大小排序(升序);
2.main函数{
    定义并输入城镇数和可通路数;
    将路径按照权重大小排序;
    
    在边集内从最小路径循环:
        如最小路径所对应的两个节点未联通:
            将这两个节点标记为联通;计数++;总花费+=单权重;
        如所有节点已联通(计数==n-1) break;
    如果计数!=n-1(所有城镇未被联通)cout<<-1<<endl;
    else cout<<总花费;
    
}


//代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

struct Edge{
    int u,v,w;
    Edge(int u,int v,int w):u(u),v(v),w(w){}

    bool operator<(const Edge& other)const{
        return w < other.w;
    }
};

class UnionFind{
    private:
    vector<int> parent;
    public:
    UnionFind(int size){
        parent.resize(size+1);
        for(int i=1;i<=size;i++){
            parent[i]=i;
        }
    }
    int find(int x){
        if(parent[x]!=x){
            parent[x]=find(parent[x]);
        }
        return parent[x];
    }
    void unite(int x,int y){
        int rootX=find(x);
        int rootY=find(y);
        if(rootX!=rootY)parent[rootY]=rootX;
    }
    bool connected(int x,int y){
        return find(x)==find(y);
    }
};

int main(){
    int n,m;
    cin>>n>>m;

    vector<Edge> edges;
    for(int i=0;i<m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        edges.emplace_back(u,v,w);
    }

    sort(edges.begin(),edges.end());

    UnionFind uf(n);
    int totalcost=0;
    int edgecount=0;

    for(const Edge& edge:edges){
        if(!uf.connected(edge.u,edge.v)){
            uf.unite(edge.u,edge.v);
            totalcost+=edge.w;
            edgecount++;

            if(edgecount==n-1)break;
        }
    }
    if(edgecount!=n-1)cout<<-1<<endl;
    else cout<<totalcost<<endl;

    return 0;
}
  

三、实验使用环境(本次实验所使用的平台和相关软件)

以下请根据实际情况编写

  • 操作系统:Windows 11
  • 编程语言:C++
  • 开发工具:visual studio2022 &pintia
  • 编译器:g++

四、实验步骤和调试过程(实验步骤、测试数据设计、测试结果分析)

任务一、二:图的创建与遍历

本机运行截图

img

任务三:图着色问题

PTA提交截图

img

任务四:公路村村通

PTA提交截图

img


五、实验小结(实验中遇到的问题及解决过程、实验体会和收获)

遇到的问题及解决方法:

vector和memset等太难 用csdn查使用方法解决。

还有两种递归的理解 通过实验课和ppt领会

在公路村村通问题中,难点集中于我提到的两个函数(权重升序排序和判断是否联通)的设计方法,这一点比较难我自己写不出来,后来也是查询得到。

实验体会和收获:

在本次实验中,我首先理解了图类型数据结构性质,在我的任务一二中通过邻接矩阵的方式创建了图并对其进行操作。在对两种遍历方式的实验中,我发现DFS(深度优先)采用嵌套递归的遍历方式,类似于树的递归遍历思想,实际操作中可能具有先序树的相关性质,但非连通图则需另外考虑;而BFS(广度优先)则借用队列进行层级优先遍历,类似于树的层级遍历。

问题解决中,在图的着色问题上引入了边集这一概念,发现在连通无向图中很实用,通过访问边就能轻松访问各个顶点,有向图或许可以用vector来使用(?)。

同时,也通过公路村村通问题理解了最小生成树在实际中的运用,这种插入逻辑方式能以很小的时空复杂度实现最优方法的创建。


六、附件(参考文献和相关资料)

posted @ 2025-05-16 13:35  KinthYu  阅读(52)  评论(0)    收藏  举报