课程设计目录
一、设计任务及要求
假设一个城市有n个小区,要实现n个小区之间的电网都能够相互接通,构造这个城市n个小区之间的电网,使总工程造价最低。请设计一个能满足要求的造价方案。
最小生成树总体功能要求:在 n 个城市之间建设网络,只需保证连通即可,求最经济的架设方法,存储结构采用多种,求解算法多种。
基本功能:在 n 个城市之间建设网络,只需要架设 n-1 条线路,建立最小生成树即可实现最经济的架设方法,程序可利用克鲁斯卡尔算法或 prim 算法生成最小生成树。
二、设计导向
1. 设计目的
- 巩固和加深对数据结构课程所学知识的理解,了解并掌握数据结构与算法的设计方法;
- 初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;
- 提高综合运用所学的理论知识和方法,独立分析和解决问题的能力;
- 训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风;
- 培养查阅资料,独立思考问题的能力。
2. 设计课题
在 n 个城市之间建设网络,只需保证连通即可,求最经济的架设方法,存储结构采用多种,求解算法多种。在 n 个城市之间建设网络,只需要架设 n-1 条线路,建立最小生成树即可实现最经济的架设方法,程序可利用克鲁斯卡尔算法或 prim 算法生成最小生成树。
3. 总体设计方案
在每个小区之间都可以设置一条电网线路,相应的都要付出一点经济代价。n个小区之间最多可以有n(n-1)/2条线路,选择其中的n-1条使总的耗费最少。可以用连通网来表示n个城市之间以及n个城市之间可能设置的电网线路,其中网的顶点表示小区,边表示两个小区之间的线路,赋予边的权值表示相应的代价。对于n个顶点的连通网可以建立许多不同的生成树,每一颗生成树都可以是一个电路网。现在,我们要选择总耗费最少的生成树,就是构造连通网的最小代价生成树的问题,一颗生成树的代价就是树上各边的代价之和。
设G=(V, E)是具有n个顶点的网络,T=(U, TE)为G的最小生成树,U是T的顶点集合,TE是T的边集合。Prim算法的基本思想是:首先从集合V中任取一顶点(例如去顶点v0)放入集合U中,这时U={ v0},TE=NULL。然后找出所有一个顶点在集合U里,另一个顶点在集合V-U里的边,使权(u, v)(u∈U, v∈V-U)最小,将该边放入TE,并将顶点v加入集合U。重复上诉操作直到U=V为止。这时TE中有n-1条边,T=(U, TE)就是G的一颗最小生成树。
4. 详细设计
(1)数据类型的定义
typedef struct
{
char D[MAXNUM];
int arcs[MAXNUM][MAXNUM];
int vexnum, arcnum;//顶点数和边数
}AMGraph;
struct//辅助数组的定义
{
char begin;
char end;
int weight;
}FuZhu[(MAXNUM * (MAXNUM - 1)) / 2];
int Vexset[MAXNUM];
(2)创建无向网G
void CreateG(AMGraph& G)//创建无向网G
{
int i, j, t;
cout << "请输入城市小区的总个数和小区之间的总电路数:";
cin >> G.vexnum >> G.arcnum;
cout << endl;
cout << "输入小区的名称:如a" << endl;
for (i = 0; i < G.vexnum; i++)
{
cout << "请输入第" << (i + 1) << "个小区的名称:";
cin >> G.D[i];
}
cout << endl;
for (i = 0; i < G.vexnum; i++)
{
for (j = 0; j < G.vexnum; j++)
G.arcs[i][j] = MAXINT;
}
cout << "请输入电路的起点,终点和造价,例如a b 4" << endl;
for (t = 0; t < G.arcnum; t++)
{
char x, y;
int z;
cout << "请输入第" << (t + 1) << "条电路的起点终点和造价:";
cin >> x >> y >> z;
i = LocateVex(G, x);
j = LocateVex(G, y);
G.arcs[i][j] = z;
G.arcs[j][i] = z;
FuZhu[t].begin = x;
FuZhu[t].end = y;
FuZhu[t].weight = z;
}
}
(3)prim算法
假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。算法从U={u0}(u0∈V)、TE={}开始。重复执行下列操作:
在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止。此时,TE中必有n-1条边,T=(V,TE)为G的最小生成树。
Prim算法的核心:始终保持TE中的边集构成一棵生成树。
5. 系统测试与结果分析
三、课程设计总结
我们课程设计的主要就是最小生成树普利姆算法的实现,在这次实践中遇到了各种问题,碰到问题有时总是百思不得其解。
在最开始,分析题目时知道本题就是书上最小生成树的问题,于是将书上内容复习一遍。在程序完成 后也出现过多次问题,比如printf后面的中文提示多次错误,另外最后的输出结果也出现问题,输出的点与实际相差1,最后修改程序的普里姆算法段完成。
除此之外,通过本次课程设计巩固了课本的基本知识,熟练运用课程知识。提高我们组织数据及编写程序的能力,使我们能够根据问题要求和数据对象的特性,学会数据组织的方法,把现实世界中的问题在计算机内部表示出来并用软件解决问题,本次实验大大提高了我们对编程的爱好。
四、附录:源程序清单
#include <iostream>
using namespace std;
#define MAXNUM 100
#define MAXINT 1000
typedef struct
{
char D[MAXNUM];
int arcs[MAXNUM][MAXNUM];
int vexnum, arcnum;//顶点数和边数
}AMGraph;
struct//辅助数组的定义
{
char begin;
char end;
int weight;
}FuZhu[(MAXNUM * (MAXNUM - 1)) / 2];
int Vexset[MAXNUM];
int LocateVex(AMGraph G, char v)//确定v在G中的位置
{
for (int i = 0; i < G.vexnum; ++i)
if (G.D[i] == v)
return i;
return -1;
}
void CreateG(AMGraph& G)//创建无向网G
{
int i, j, t;
cout << "请输入城市小区的总个数和小区之间的总电路数:";
cin >> G.vexnum >> G.arcnum;
cout << endl;
cout << "输入小区的名称:如a" << endl;
for (i = 0; i < G.vexnum; i++)
{
cout << "请输入第" << (i + 1) << "个小区的名称:";
cin >> G.D[i];
}
cout << endl;
for (i = 0; i < G.vexnum; i++)
{
for (j = 0; j < G.vexnum; j++)
G.arcs[i][j] = MAXINT;
}
cout << "请输入电路的起点,终点和造价,例如a b 4" << endl;
for (t = 0; t < G.arcnum; t++)
{
char x, y;
int z;
cout << "请输入第" << (t + 1) << "条电路的起点终点和造价:";
cin >> x >> y >> z;
i = LocateVex(G, x);
j = LocateVex(G, y);
G.arcs[i][j] = z;
G.arcs[j][i] = z;
FuZhu[t].begin = x;
FuZhu[t].end = y;
FuZhu[t].weight = z;
}
}
void Sort(AMGraph G)//冒泡排序
{
int m = G.arcnum - 2;
int n = 1;
while ((m > 0) && n == 1)
{
n = 0;
for (int j = 0; j <= m; j++)
{
if (FuZhu[j].weight > FuZhu[j + 1].weight)
{
n = 1;
char Begin = FuZhu[j].begin;
FuZhu[j].begin = FuZhu[j + 1].begin;
FuZhu[j + 1].begin = Begin;
char End = FuZhu[j].end;
FuZhu[j].end = FuZhu[j + 1].end;
FuZhu[j + 1].end = End;
char Weight = FuZhu[j].weight;
FuZhu[j].weight = FuZhu[j + 1].weight;
FuZhu[j + 1].weight = Weight;
}
}
}
}
int MinSpanTree(AMGraph G)//构造最小生成树
{
int i, j, v1, v2, m, n, sum=0;
Sort(G);
for (i = 0; i < G.vexnum; i++)
{
Vexset[i] = i;
}
for (i = 0; i < G.arcnum; i++)
{
v1 = LocateVex(G, FuZhu[i].begin);
v2 = LocateVex(G, FuZhu[i].end);
m = Vexset[v1];
n = Vexset[v2];
if (m != n)
{
sum += FuZhu[i].weight;
cout << FuZhu[i].begin << "-->" << FuZhu[i].end << endl;
for (j = 0; j < G.vexnum; j++)
{
if (Vexset[j] == n)
Vexset[j] = m;
}
}
}
return sum;
}
int main()
{
int money;
AMGraph G;
CreateG(G);
cout << endl;
cout << "******无向网创建完成******" << endl;
cout << endl;
money = MinSpanTree(G);
cout << "电路总造价为:" << money << endl;
return 0;
}