#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<stack>// 用 stl 栈 存储
#define MAXSIZE 1000
using namespace std;
Kruskal算法 生成最小生成树
/******
测试样本1:
5
1 2 3
2 3 4
4 5 6
2 4 3
5 2 8
1 4 1
3 5 7
1 5 2
0 0 0//8组数据
//标准测试数据(题目给的):
9
1 2 32.8
1 3 44.6
1 8 12.1
1 9 18.2
2 3 5.9
3 4 21.3
3 5 41.1
3 7 56.4
4 5 67.3
4 6 98.7
5 6 85.6
5 7 10.5
6 9 79.2
7 8 52.5
8 9 8.7
0 0 0
*******/
/*
程序实现流程:
1.输入数据
2.处理输入数据,对数据进行排序
3.寻找最小生成树
4.输出算法结果
5.a.对图进行修改 修改后返回2
b.重新输入数据(即返回1)
c.退出程序
************/
/
int ver_num;//点的个数
int vertex[MAXSIZE];//点数组 用于确定点的集合 用并查集确定点是否在同一集合内
typedef struct edge
{
int v1, v2;
double weight;
}Edge, *Edge_ptr;//边
Edge_ptr G_Edge[MAXSIZE];//边数组 边的排序采用选择排序
int G_Edge_n;//边个数
stack<Edge> S;//栈用来存储算法结果
bool flag;//用来表示是否找到 最小生成树 1表示成功 0表示失败
void input()
{
int a, b;double w;
printf("input the number of vertex:");
scanf_s("%d", &ver_num);
getchar();//吸收回车
printf("the ver(s) you can use are:");
for (int i = 1; i <= ver_num; i++) printf("%4d", i);
printf("\n");
int j = 0;
printf("请输入边信息:(如1 2 3.5)(表示点1和点2直接的距离为3.5)(输入0 0 0代表输入结束)\n");
printf("请输入边信息(v v w):");
while (scanf_s("%d %d %lf", &a, &b, &w) && a && b && w)
{
getchar();
Edge_ptr t;
if (!(t = (Edge_ptr)malloc(sizeof(Edge)))) exit(1);
t->v1 = a; t->v2 = b; t->weight = w;
j++;
G_Edge[j] = t;
printf("请输入边信息(v v w):");
}
getchar();
printf("输入结束\n\n");
G_Edge_n = j;
printf("you have input %d vers and %d edges\n", ver_num, G_Edge_n);
}
void mysort()
{//选择排序法
int num = G_Edge_n;//对 索引为 1 到 num 的边数组进行排序
int i, j, k;
Edge_ptr t;
for (i = 1; i < num; i++)//找出当前第i条边
{
k = i;//用k代表当前的最小的边
for (j = k + 1; j <= num; j++)
{
if (G_Edge[j]->weight < G_Edge[k]->weight) k = j;//如果第j条边的权 比第k条边小 那么让k=j;让k始终指向当前权值最小的边
}
//swap k,i
if (k != i)//如果第i条边不是最小的 就让k和i交换 是第i条边成为当前最小的边
{
t = G_Edge[k]; G_Edge[k] = G_Edge[i]; G_Edge[i] = t;
}
}
}
int find(int t)//寻找点t所属于的 最终点的集合
{
if (t == vertex[t]) return t;
else return find(vertex[t]);
}
int is_in(int a, int b)
{//判断点a和点b是否在同一集合里
return find(a) == find(b);// true 则表示 a 已经在一个集合里了
}
int union_v(int a, int b)
{//使不在统一集合里的两个点 成为同一个集合 即添加一条端点为ab的边
if (is_in(a, b)) return 0;//两个点本来就在一个结合里面
int x = find(a), y = find(b);
vertex[x] = y;
return 1;//通过一条边 将两个集合 合并为一个集合
}
void solve()
{//kruskal算法求最小生成树
int i;
int e_num = 0;//e_num用来表示 已经选定的边的个数
//init ver[]
for (int i = 1; i <= ver_num; i++) vertex[i] = i;//初始化点数组
for (i = 1; i <= G_Edge_n && e_num < ver_num - 1; i++)
{
if (is_in(G_Edge[i]->v1, G_Edge[i]->v2)) continue;//如果该边可以连成回路 则放弃该边
union_v(G_Edge[i]->v1, G_Edge[i]->v2);//否则 确定该边 使两端点 在同一个集合中
e_num++;//
S.push(*G_Edge[i]);//将这条边存储在栈中
}
if (e_num == ver_num - 1) flag = 1;//如果 e_num==ver_num-1 表示 找到了最小生成树 flag=1;
else flag = 0;//没找到
}
void output()//输出算法结果
{
printf("************************************************\n");
Edge tt;
if (flag == 1)//如果找到的话
{
printf("找到最小生成树\n");
printf("构成最小生成树的边如下(v v w):\n");
while (!S.empty())
{
tt = S.top(); S.pop();
printf("%d %d %.1lf\n", tt.v1, tt.v2, tt.weight);
}
}
else printf("kruskal failed!\n-.-\n");//没找到的话
printf("************************************************\n");
}
void AddVer()//新增一个点
{
ver_num++;
printf("增加一个节点%d,当前有%d个节点\n", ver_num, ver_num);
}
//void DelVer()//删除一个点{ ;}//没要求写
void AddEdge()//新增一条边
{
int a, b; double w;
printf("请输入边信息(v v w):");
scanf_s("%d %d %lf", &a, &b, &w);
getchar();
Edge_ptr t;
if (!(t = (Edge_ptr)malloc(sizeof(Edge)))) exit(1);
t->v1 = a; t->v2 = b; t->weight = w;
G_Edge_n++;
G_Edge[G_Edge_n] = t;
printf("新增一条边 (%d,%d,%4.1lf),当前%d条边\n", G_Edge[G_Edge_n]->v1, G_Edge[G_Edge_n]->v2, G_Edge[G_Edge_n]->weight, G_Edge_n);
}
//void DelEdge(){ ; }//没要求写
void alter()
{
//a.增加一个点
b.减少一个点
//c.增加一条边
d.减少一条边
//e.修改完毕,重新计算
char cc;
while (1)
{
//choose menu
printf(" a.增加一个点\n");
//printf("b.减少一个点\n");
printf(" c.增加一条边\n");
//printf("d.减少一条边\n");
printf(" e.修改完毕,重新计算\n");
cc = getchar();
getchar();
switch (cc)
{
case 'a':AddVer();
break;
//case 'b': DelVer(); break;
case 'c':AddEdge();
break;
//case 'd':DelEdge(); break;
case 'e':
break;
}
if (cc == 'e')break;
}
}
void menu(int i)
{
if (i == 1)
{
printf("*****************************************************\n");
printf("** **\n");
printf("** 课程设计报告 **\n");
printf("** **\n");
printf("*****************************************************\n");
printf("** **\n");
printf("**管道铺设施工 **\n");
printf("**【问题描述】 **\n");
printf("**需要在某个城市的n个居民区之间铺设煤气管道,则在这**\n");
printf("**n个居民区之间只要铺设n - 1条管道即可。假设任意两 **\n");
printf("**个居民区之间都可以架设管道,但由于地理环境的不同 **\n");
printf("**,所需经费不同。选择最优的施工方案能使投资尽可能 **\n");
printf("**少,这个问题即为求网络的最小生成树。 **\n");
printf("** **\n");
printf("*****************************************************\n");
}
else
{
printf("*****************************************************\n");
printf("** **\n");
printf("** 课程设计报告完毕 **\n");
printf("** **\n");
printf("*****************************************************\n");
}
}
//主函数
int main()
{
char c;
menu(1);//start menu
while (1)
{
input();
while (1)
{
mysort();
solve();
output();
//choose menu
printf(" a.修改图\n");
printf(" b.输入新图\n");
printf(" c.退出程序\n");
printf("choose:");
c = getchar();
getchar();
if (c == 'a')
{
alter();
continue;
}
else if (c == 'b' || c == 'c')
{
break;
}
else printf("input error!\n");
}
if (c == 'c') break;
}
//end menu
menu(2);
return 0;
}
kruskal算法..
最新推荐文章于 2024-08-19 16:43:37 发布