目录
1.题目
问题描述:在几个城市之间建设网络(不少于15个),只需要保证联通即可,求最经济的架设方案
具体要求如下:
- 创建图:从文件中读入图的数据信息
- 管理图:增加新的城市结点,增加一条网络,删除一个城市结点(只有没有网络连线的城市才能删除),删除一条网络连线,保存图的信息到文件
- 利用prim或kruscal算法得到最小生成树
- 设计界面实现图以及最小生成树(加分项)
2.功能思维导图
3.网点图
4.流程图
5.函数调用关系
6.案例代码
#include<stdio.h>
#include<stdlib.h>
#include <conio.h>
#include <string.h>
#define MaxVertices 100 //假设包含100个顶点
#define MaxWeight 32767 //不邻接时为32767,但输出时用 "∞"
#define MAX_PASSWORD_LENGTH 20
#define MAX_SIZE 100
#define V 15
typedef struct { //包含权的邻接矩阵的的定义
int Vertices[MaxVertices]; //顶点信息的数组
int Edge[MaxVertices][MaxVertices]; //边的权信息的数组
int numV; //当前的顶点数
int numE; //当前的边数
}AdjMatrix;
void CreateGraph(AdjMatrix* G) //图的生成函数
{
int spot[99] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
int v1[99] = { 1,1,2,3,5,5,6,6,8,10,10,11,13,14 };
int v2[99] = { 2,3,4,5,7,6,8,9,11,12,11,13,14,15 };
int weight[15] = { 3,5,4,2,1,4,3,2,2,2,4,1,2,4 };
int n, e, vi, vj, w, i, j;
n = 15; e = 14;
G->numV = n; G->numE = e;
for (i = 0; i < n; i++) //图的初始化
for (j = 0; j < n; j++) {
if (i == j)
G->Edge[i][j] = 0;
else
G->Edge[i][j] = MaxWeight;
}
for (i = 0; i < G->numV; i++) //将顶点存入数组中
G->Vertices[i] = spot[i];
printf("\n");
for (i = 0; i < G->numE; i++) {
vi = v1[i];
vj = v2[i];
w = weight[i];
G->Edge[vi - 1][vj - 1] = w;//①
G->Edge[vj - 1][vi - 1] = w;//②
}
}
void DispGraph(AdjMatrix G) //输出邻接矩阵的信息
{
int i, j;
printf("\n输出顶点的信息(整型):\n");
for (i = 0; i < G.numV; i++)
printf("%8d", G.Vertices[i]);
printf("\n");
printf("\n输出邻接矩阵:\n");
printf("\t");
for (i = 0; i < G.numV; i++)
printf("%8d", G.Vertices[i]);
for (i = 0; i < G.numV; i++)
{
printf("\n%8d", i + 1);
for (j = 0; j < G.numV; j++)
{
if (G.Edge[i][j] == 32767)
//两点之间无连接时权值为默认的32767,
printf("%8s", "∞");
else
printf("%8d", G.Edge[i][j]);
}
printf("\n");
}
}
//查找节点信息函数
void SearchNet(AdjMatrix G) {
int net;
CreateGraph(&G);
printf("请输入想要查询的网点:\n");
scanf_s("%d",&net);
printf("您输入的站点是%d\n", net);
if (net == 1 || net == 2 || net ==3)
{
printf("所属城市---深圳\n");
}
else if (net == 4 || net == 5 || net == 6)
{
printf("所属城市---东莞\n");
}
else if (net == 7 || net == 8 || net == 9)
{
printf("所属城市---汕头\n");
}
else if (net == 10 || net == 11 || net == 12)
{
printf("所属城市---揭阳\n");
}
else if (net == 13 || net == 14 || net == 15)
{
printf("所属城市---广州\n");
}
else
{
printf("输入有误请重新输入");
SearchNet(G);
}
net--;
for (int i = 0; i < V-1; i++)
{
if (G.Edge[net][i]>0 && G.Edge[net][i]<32767)
{
printf("相邻网点");
printf("%d", i+1);
printf(" ");
printf("站点距离为%dkm",G.Edge[net][i]);
printf("\n");
}
}
printf("\n");
printf("\n");
printf("\n");
}
//验证管理员函数
int Prove() {
char password[MAX_PASSWORD_LENGTH + 1];
int i = 0;
char ch;
printf("Please enter your password: ");
while (i < MAX_PASSWORD_LENGTH && (ch = _getch()) != '\r') {
if (ch == '\b') {
if (i > 0) {
putchar('\b');
putchar(' ');
putchar('\b');
i--;
}
}
else if (ch >= ' ' && ch <= '~') {
putchar('*');
password[i++] = ch;
}
}
putchar('\n');
password[i] = '\0';
if (strcmp(password, "admin") == 0) {
// 执行C函数
system("cls");
printf("Login success!\n");
return 1;
}
else {
system("cls");
printf("Invalid password.\n");
return 0;
}
}
//最短路径
int minDistance(int dist[], bool sptSet[]) {
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
{
if (sptSet[v] == false && dist[v] <= min)
{
min = dist[v];
min_index = v;
}
}
return min_index;
}
//缔结克拉斯最短路径算法
void dijkstra(AdjMatrix G, int src, int dest) {
int dist[V]; // 存储最短距离
bool sptSet[V]; // 存储已计算的顶点集合
for (int i = 0; i < V; i++) {
dist[i] = INT_MAX;
sptSet[i] = false;
}
dist[src] = 0;
for (int count = 0; count < V - 1; count++) {
int u = minDistance(dist, sptSet);
sptSet[u] = true;
for (int v = 0; v < V; v++) {
if (!sptSet[v] && G.Edge[u][v] && dist[u] != INT_MAX
&& dist[u] + G.Edge[u][v] < dist[v])
dist[v] = dist[u] + G.Edge[u][v];
}
}
// 打印最短路径结果
printf("\nShortest distance from %d to %d is: %d\n", src + 1, dest + 1, dist[dest]);
}
//普利姆算法实现最小生成树
int dist[MAX_SIZE]; // 用于存储每个节点到最小生成树的最小距离
bool visited[MAX_SIZE]; // 用于记录节点是否已经被访问
int parent[MAX_SIZE]; // 记录节点在最小生成树中的父节点
void prim(int n, int s, AdjMatrix G) {
for (int i = 1; i <= n; i++) {
visited[i] = false;
dist[i] = MaxWeight;
parent[i] = -1;
}
int ans = 0;
dist[s] = 0;
while (true) {
int v = -1;
for (int i = 1; i <= n; i++) {
if (!visited[i] && (v == -1 || dist[i] < dist[v]))
v = i;
}
if (v == -1)
break;
visited[v] = true;
ans += dist[v];
for (int i = 1; i <= n; i++) {
if (!visited[i] && G.Edge[v - 1][i - 1] < dist[i]) {
dist[i] = G.Edge[v - 1][i - 1];
parent[i] = v;
}
}
}
printf("最小生成树边集合:\n");
for (int i = 1; i <= n; i++) {
if (parent[i] != -1) {
printf("(%d, %d)\n", parent[i], i);
}
}
printf("最小生成树的总权值为:%d\n", ans);
}
//文件读取函数
void FoldWriter() {
FILE *fp;
AdjMatrix G;
CreateGraph(&G);
if (fopen_s(&fp, "user.txt", "w") != 0)
{
printf("打开文件失败");
return;
}
int i, j;
fprintf(fp, "\n输出顶点的信息(整型):\n");
for (i = 0; i < G.numV; i++)
fprintf(fp, "%8d", G.Vertices[i]);
fprintf(fp, "\n");
fprintf(fp, "\n输出邻接矩阵:\n");
fprintf(fp, "\t");
for (i = 0; i < G.numV; i++)
fprintf(fp, "%8d", G.Vertices[i]);
for (i = 0; i < G.numV; i++)
{
fprintf(fp, "\n%8d", i + 1);
for (j = 0; j < G.numV; j++)
{
if (G.Edge[i][j] == 32767)
fprintf(fp, "%8s", "∞");
else
fprintf(fp, "%8d", G.Edge[i][j]);
}
fprintf(fp, "\n");
}
fclose(fp);
printf("cpoy 成功已保存到user.txt文件中\n");
}
//删除网点之间的连线
void DeleteEdge() {
AdjMatrix G;
CreateGraph(&G);
int netNo1;
int Netno2;
printf("原图为:");
DispGraph(G);
printf("输入你想删除的第一个edge的节点");
scanf_s("%d",&netNo1);
printf("输入你想删除的第二个edge的节点");
scanf_s("%d",&Netno2);
netNo1--;
Netno2--;
if (G.Edge[netNo1][Netno2]!=0 && G.Edge[netNo1][Netno2]!= 32767)
{
G.Edge[netNo1][Netno2] = 32767;
G.Edge[Netno2][netNo1] = 32767;
}
else
{
printf("输入两点有误请重新输入");
DeleteEdge();
}
DispGraph(G);
//写入文件
FILE *fp;
if (fopen_s(&fp, "user.txt", "w") != 0)
{
printf("打开文件失败");
return;
}
int i, j;
fprintf(fp, "\n输出顶点的信息(整型):\n");
for (i = 0; i < G.numV; i++)
fprintf(fp, "%8d", G.Vertices[i]);
fprintf(fp, "\n");
fprintf(fp, "\n输出邻接矩阵:\n");
fprintf(fp, "\t");
for (i = 0; i < G.numV; i++)
fprintf(fp, "%8d", G.Vertices[i]);
for (i = 0; i < G.numV; i++)
{
fprintf(fp, "\n%8d", i + 1);
for (j = 0; j < G.numV; j++)
{
if (G.Edge[i][j] == 32767)
fprintf(fp, "%8s", "∞");
else
fprintf(fp, "%8d", G.Edge[i][j]);
}
fprintf(fp, "\n");
}
fclose(fp);
}
//增加节点连线
void AddEdge() {
AdjMatrix G;
CreateGraph(&G);
int netNo1;
int Netno2;
int weight;
printf("原图为");
DispGraph(G);
printf("输入你想增加的第一个edge的节点");
scanf_s("%d", &netNo1);
printf("输入你想增加的第二个edge的节点");
scanf_s("%d", &Netno2);
printf("输入连接节点的权值");
scanf_s("%d", &weight);
netNo1--;
Netno2--;
if (G.Edge[netNo1][Netno2]==0 || G.Edge[netNo1][Netno2]< 32767)
{
printf("输入节点有误请重新输入");
AddEdge();
}
else
{
G.Edge[netNo1][Netno2] = weight;
G.Edge[Netno2][netNo1] = weight;
DispGraph(G);
}
//file writen
FILE *fp;
if (fopen_s(&fp, "user.txt", "w") != 0)
{
printf("打开文件失败");
return;
}
int i, j;
fprintf(fp, "\n输出顶点的信息(整型):\n");
for (i = 0; i < G.numV; i++)
fprintf(fp, "%8d", G.Vertices[i]);
fprintf(fp, "\n");
fprintf(fp, "\n输出邻接矩阵:\n");
fprintf(fp, "\t");
for (i = 0; i < G.numV; i++)
fprintf(fp, "%8d", G.Vertices[i]);
for (i = 0; i < G.numV; i++)
{
fprintf(fp, "\n%8d", i + 1);
for (j = 0; j < G.numV; j++)
{
if (G.Edge[i][j] == 32767)
fprintf(fp, "%8s", "∞");
else
fprintf(fp, "%8d", G.Edge[i][j]);
}
fprintf(fp, "\n");
}
fclose(fp);
}
//Delete Node function
void DeleteNode() {
int Node;
int i,j;
AdjMatrix G;
CreateGraph(&G);
printf("please input which Node ");
scanf_s("%d",&Node);
Node--;
printf("\n输出顶点的信息(整型):\n");
for (i = 0; i < G.numV; i++) {
if (i!= Node)
{
printf("%8d", G.Vertices[i]);
}
}
printf("\n");
printf("\n输出邻接矩阵:\n");
printf("\t");
for (i = 0; i < G.numV; i++)
{
for (j = 0; j < G.numV; j++)
{
if (i== Node || j==Node)
{
printf(" ");
}
else
{
printf("%8d", G.Edge[i][j]);
}
}
printf("\n");
}
//将记录写入文件
}
//管理员UI系统
void manegeUI() {
printf(" 城市网点管理系统:\n");
printf("\n");
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
printf("\n");
printf(" 一。 -- 删除网点线路\n");
printf(" 二。 -- 增加网点线路\n");
printf(" 三。 -- 删除某一节点\n");
printf(" 0 — 退出\n");
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
printf("\n");
printf("请输入您所需要用的功能: ");
int Mflag;
scanf_s("%d", &Mflag); // 读取用户输入
switch (Mflag)
{
case 1:
DeleteEdge();
printf("成功执行函数,按0结束程序,按1则重新回到页面");
scanf_s("%d", &Mflag);
while (Mflag != 0 && Mflag != 1)
{
printf("输入有误请重新输入");
scanf_s("%d", &Mflag);
}
if (Mflag == 1)
{
system("cls");
manegeUI();
}
break;
case 2:
AddEdge();
printf("成功执行函数,按0结束程序,按1则重新回到页面");
scanf_s("%d", &Mflag);
while (Mflag != 0 && Mflag != 1)
{
printf("输入有误请重新输入");
scanf_s("%d", &Mflag);
}
if (Mflag == 1)
{
system("cls");
manegeUI();
}
break;
case 3:
DeleteNode();
printf("成功执行函数,按0结束程序,按1则重新回到页面");
scanf_s("%d", &Mflag);
while (Mflag != 0 && Mflag != 1)
{
printf("输入有误请重新输入");
scanf_s("%d", &Mflag);
}
if (Mflag == 1)
{
system("cls");
manegeUI();
}
break;
case 0:
break;
default:
system("cls");
printf("输入无效参数,请重新输入");
manegeUI();
break;
}
}
//实现用户UI系统
void Ui() {
printf(" 城市网点交通系统:\n");
printf("\n");
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
printf("\n");
printf(" 一。 -- 输出路线的邻接矩阵\n");
printf(" 二。 -- 最短路径功能\n");
printf(" 三。 -- 实现最小生成树功能\n");
printf(" 四。 -- 保存网点文件到用户目录\n");
printf(" 五。 -- 查询某网点的具体信息\n");
printf(" 六。 -- 进入管理员系统\n");
printf(" 0 — 退出\n");
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
printf("\n");
printf("请输入您所需要用的功能: ");
int flag;
scanf_s("%d", &flag); // 读取用户输入
switch (flag) {
case 0://退出
break;
case 1://输出map
AdjMatrix G;
CreateGraph(&G);
int flags;
system("cls");
DispGraph(G);
printf("成功执行函数,按0结束程序,按1则重新回到页面");
scanf_s("%d", &flags);
while (flags!= 0 && flags!=1)
{
printf("输入有误请重新输入");
scanf_s("%d", &flags);
}
if (flags == 1)
{
system("cls");
Ui();
}
break;
case 2://input minest road
int src, dest;
printf("请输入起点");
scanf_s("%d", &src);
printf("请输入终点");
scanf_s("%d", &dest);
src--; dest--;
//AdjMatrix G;
CreateGraph(&G);
dijkstra(G, src, dest);
printf("成功执行函数,按0结束程序,按1则重新回到页面");
scanf_s("%d", &flags);
while (flags != 0 && flags != 1)
{
printf("输入有误请重新输入");
scanf_s("%d", &flags);
}
if (flags == 1)
{
system("cls");
Ui();
}
break;
case 3: //minest tree
CreateGraph(&G);
prim(V, 1, G);
memset(dist, 0, sizeof(dist));
memset(visited, false, sizeof(visited));
memset(parent, -1, sizeof(parent));
printf("成功执行函数,按0结束程序,按1则重新回到页面");
scanf_s("%d", &flags);
while (flags != 0 && flags != 1)
{
printf("输入有误请重新输入");
scanf_s("%d", &flags);
}
if (flags == 1)
{
system("cls");
Ui();
}
break;
case 4:
//folder woriting
FoldWriter();
printf("成功执行函数,按0结束程序,按1则重新回到页面");
scanf_s("%d", &flags);
while (flags != 0 && flags != 1)
{
printf("输入有误请重新输入");
scanf_s("%d", &flags);
}
if (flags == 1)
{
system("cls");
Ui();
}
break;
break;
case 5:
system("cls");
SearchNet(G);
printf("成功执行函数,按0结束程序,按1则重新回到页面");
scanf_s("%d", &flags);
while (flags != 0 && flags != 1)
{
printf("输入有误请重新输入");
scanf_s("%d", &flags);
}
if (flags == 1)
{
system("cls");
Ui();
}
break;
break;
case 6:
int sentense;
sentense = Prove();
if (sentense == 1)
{
manegeUI();
}
else
{
Ui();
}
break;
default:
system("cls");
printf("选择无效,请重新输入。\n");
Ui();
break; // 跳出switch语句
}
}
int main()
{
Ui();
}
7.代码测试
1.用户
2.网点信息
最短路径
最小生成树
文件保存