实验5-图

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

项目名称 内容
课程名称 数据结构
实验项目名称
上机实践日期 2026.06.02
上机实践时间 2学时

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

  • 掌握图的邻接矩阵存储结构的创建与基本操作实现。
  • 学习编写图的深度优先搜索(DFS)和广度优先搜索(BFS)遍历算法。
  • 理解并实现图着色问题的判定算法。
  • 掌握最小生成树(Prim)原理与编码实现,完成公路村村通问题。

二、实验内容与设计思想

题目1:图的创建

函数相关伪代码

图的创建函数(顶点数n,边数e)
    初始化大小为n*n的矩阵,所有元素设置为0
    使用for循环输入n个顶点的编号
    使用for循环输入边的两个顶点u,v
        矩阵中双向赋值(表示有边)

//时间复杂度:O(n^2)
//空间复杂度:O(n^2)

函数代码

void CreateGraph(Graph &g) {
	cout << "请输入顶点数和边数:";
	cin >> g.vertexnum >> g.edgenum;
	memset(g.edge, 0, sizeof(g.edge));
	for (int i = 0; i < g.vertexnum; i++) {
		cout << "请输入顶点编号" << i << ":";
		cin >> g.vertex[i];
	}
	for (int i = 0; i < g.edgenum; i++) {
		int u, v;
		cout << "请输入边的下标:";
		cin >> u >> v;
		g.edge[u][v] = 1;
		g.edge[v][u] = 1;
	}
}

题目2:图的遍历(DFS、BFS)

函数相关伪代码

深度优先搜索函数DFS(起始顶点v)
    访问顶点v,标记为已访问
    使用for循环遍历所有顶点i
        如果edge[v][i]==1(存在边)且i未访问
            递归调用DFS(i)

广度优先搜索函数BFS(起始顶点v)
    创建队列,v入队,标记为已访问
    使用while循环遍历(当队列不为空)
        出队队首元素u,访问u
        使用for循环遍历所有顶点i
            如果edge[v][i]==1(存在边)且i未访问
                标记i为已访问,并入队

//时间复杂度:O(n^2)
//空间复杂度:O(n)

函数代码

void DFS(Graph& g, int v, bool visited[]) {
	cout << g.vertex[v] << " ";
	visited[v] = true;
	for (int i = 0; i < g.vertexnum; i++) {
		if (g.edge[v][i] == 1 && !visited[i]) {
			DFS(g,i, visited);
		}
	}
}
void DFSTraverse(Graph& g) {
	bool visited[MAX] = { false };
	cout << "DFS遍历:";
	for (int i = 0; i < g.vertexnum; i++) {
		if (!visited[i]) {
			DFS(g,i, visited);
		}
	}
	cout << endl;
}
void BFS(Graph& g, int v, bool visited[]) {
	queue<int>q;
	cout << g.vertex[v] << " ";
	visited[v] = true;
	q.push(v);
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		for (int i = 0; i < g.vertexnum; i++) {
			if (g.edge[u][i] == 1 && !visited[i]) {
				visited[i] = true;
				q.push(i);
			}
		}
	}
}
void BFSTraverse(Graph& g) {
	bool visited[MAX] = { false };
	cout << "BFS遍历:";
	for (int i = 0; i < g.vertexnum; i++) {
		if (!visited[i]) {
			BFS(g,i, visited);
		}
	}
	cout << endl;
}

题目3:图着色问题

函数相关伪代码

    输入V,e,k
    定义边集合edges[]=空列表
    使用for循环e次
        输入边的两个顶点u,v
        将边(u,v)添加到edges
    输入方案数量n
    使用while循环n次
        定义颜色数组color[v]
        使用for循环v次
            输入color[i]
        统计color数组中不重复的颜色数量used
        如果used>k
            输出No,继续下一个方案
        定义标记valid=true
        遍历edges的每一条边(u,v)
            如果color[u]==color[v]
                valid=false
        如果vaild==true输出Yes否则输出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;
	while(n--) {
		vector<int> color(V + 1);
		for (int i = 1; i < V + 1; i++) {
			cin >> color[i];
		}
		bool colorv = true;
		for (int i = 1; i < V + 1; i++) {
			if (color[i]<1 || color[i]>V) {
				colorv = false;
				break;
			}
		}
		if (!colorv) {
			cout << "No\n";
			continue;
		}
		set<int>used;
		for (int i = 1; i < V + 1; i++) {
			used.insert(color[i]);
		}
		if (used.size() != k) {
			cout << "No\n";
			continue;
		}
		bool valid = true;
		for (auto& edge : edges) {
			int u = edge.first;
			int v = edge.second;
			if (color[u] == color[v]) {
				valid = false;
				break;
			}
		}
		cout << (valid ? "Yes\n" : "No\n");
	}
	return 0;
}

题目4:公路村村通(最小生成树)

函数相关伪代码

    //图的数据结构
    typedef struct{
        edges[][];//邻接矩阵:存储公路成本
        int n,m;
    }Mygraph;
    //公路村村通解题大致步骤
    总修路成本 total = 0
    整型 road[]  // 生成树到每个村落的最小边权
    布尔型 visited[] // 标记村落是否已接入公路网
    定义最低成本total
    读取城镇数目n,候选道路数目m
    初始化邻接矩阵所有值为INF
    初始化road数组全为INF
    初始化visited数组全为false
    使用for循环m次
        读取两个城镇编号u,v和预算成本w
        Mygraph.edges[u][v]=w
        Mygraph.edges[v][u]=w //无向公路,双向赋值
    以村落1为起点road[1]=0
    使用for循环n-1次
    初始化最小成本minr=inf,v=-1
    //找到未访问顶点中road最小边权的村落v
    使用for循环遍历所有村落j
        if 未访问村落且路径小于当前最短路径
            minr=road[j] //更新最小边权
            v=j 
    //找不到,说明输入数据不足以保持畅通
    if(v=-1||minr=inf)
        输出-1并返回,说明需要建设更多公路
    visited[v]=true 
    total+=minr //累加成本
    使用for循环遍历所有村落j
         if(未访问且Mygraph.edges[v][j]<road[j])
             更新最小边权

函数代码

#include <iostream>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1005;
struct MyGraph {
	int edges[MAXN][MAXN]; 
	int n, m;               
} G;
int main() {
	int road[MAXN];   
	bool visited[MAXN];
	int total = 0; 
	memset(road, 0x3f, sizeof(road));    
	memset(visited, false, sizeof(visited)); 
	memset(G.edges, 0x3f, sizeof(G.edges));
	cin >> G.n >> G.m;
	for (int i = 0; i < G.m; ++i) {
		int u, v, w;
		cin >> u >> v >> w;
		G.edges[u][v] = w;
		G.edges[v][u] = w;
	}
	road[1] = 0;
	for (int i = 1; i <= G.n; ++i) {
		int minr = INF;
		int v = -1;
		for (int j = 1; j <= G.n; ++j) {
			if (!visited[j] && road[j] < minr) {
				minr = road[j];
				v = j;
			}
		}
		if (v == -1 || minr == INF) {
			cout << - 1 << endl;
			return 0;
		}
		visited[v] = true;
		total += minr;
		for (int j = 1; j <= G.n; ++j) {
			if (!visited[j] && G.edges[v][j] < road[j]) {
				road[j] = G.edges[v][j];
			}
		}
	}
	cout << total << endl;
	return 0;
}

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

  • 操作系统:Windows 11专业版
  • 编程语言:C++
  • 开发工具Visual Studio 2026
  • 编译器:vs2026默认编译器、g++

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

题目1:图的创建

本机运行截图
image

题目2:图的遍历

本机运行截图
image

题目3:图着色问题

本机运行截图
image

PTA提交截图
image

题目4:公路村村通

本机运行截图
image

PTA提交截图
image

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

遇到的问题及解决方法:

  1. 问题:BFS队列未正确入队。
    • 解决方法:入队时顶点同步标记为已访问,防止重复入队。
  2. 问题:Prim算法权值计算错误。
    • 解决方法:双向赋值边权。

实验体会和收获:

  • 掌握了图的邻接矩阵存储,理解无向图和有向图的存储差异。
  • 实现DFS和BFS图的遍历算法操作,加深对这两种遍历的核心思想的理解。
  • 学会通过AI对话调试最小生成树代码,提升了问题排查和代码修改能力。
  • 进一步掌握了伪代码的编写规范,算法逻辑更加清晰。

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

  1. 实验5-图
  2. 使用AI辅助编写报告的建议
posted @ 2026-06-02 23:36  xin_fffffly  阅读(0)  评论(0)    收藏  举报