实验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:图的创建
本机运行截图

题目2:图的遍历
本机运行截图

题目3:图着色问题
本机运行截图

PTA提交截图

题目4:公路村村通
本机运行截图

PTA提交截图
![image]()
五、实验小结(实验中遇到的问题及解决过程、实验体会和收获)
遇到的问题及解决方法:
- 问题:BFS队列未正确入队。
- 解决方法:入队时顶点同步标记为已访问,防止重复入队。
- 问题:Prim算法权值计算错误。
- 解决方法:双向赋值边权。
实验体会和收获:
- 掌握了图的邻接矩阵存储,理解无向图和有向图的存储差异。
- 实现DFS和BFS图的遍历算法操作,加深对这两种遍历的核心思想的理解。
- 学会通过AI对话调试最小生成树代码,提升了问题排查和代码修改能力。
- 进一步掌握了伪代码的编写规范,算法逻辑更加清晰。


浙公网安备 33010602011771号