题目:
利用普里姆(Prim)算法或克鲁斯卡尔(Kruskal)算法求上图的最小生成树
思路:
(1) 普利斯的邻接矩阵算法:从已选顶点所关联的未选边中找出权重最小的边,并且生成树不存在环。其中,已选顶点是构成最小生成树的结点,未选边是不属于生成树中的边。
(2) A.将边按权值从小到大的顺序添加到新图中,保证添加的过程中不会形成环
B.重复上一步直到连接所有顶点,此时就生成了最小生成树。这是一种贪心策略。
代码块:
#include "pch.h"
#include <iostream>
#include<queue>
using namespace std;
#define MVNum 100
#define INFINITY 65535
typedef char VerTexType;//顶点数据类型设置为字符
typedef int ArcType;//边的权值为整型
typedef int OtherInfo;
bool visited[MVNum] = { false };
/*********普里姆算法***********/
struct AMGraph {
VerTexType vexs[MVNum];//顶点表
ArcType arcs[MVNum][MVNum];//邻接矩阵
int vexnum;//顶点数量
int arcnum;//边数量
};
struct Closedge {//辅助数组结构
ArcType lowcost;//权值
VerTexType adjvex;//顶点
};
int Locatevex(AMGraph G, VerTexType v)//定位顶点下标
{
for (int i = 0; i < G.vexnum; i++)//遍历寻找对应顶点下标
{
if (G.vexs[i] == v)
{
return i;
}
}
cout << "顶点输入错误,请重新检查!" << endl;//顶点输入错误处理
return -1;
}
void CreateUDN(AMGraph&G)
{
cout << "请依次输入总顶点数和总边数:";
cin >> G.vexnum >> G.arcnum;
cout << "请输入各顶点信息:" << endl;
for (int i = 0; i < G.vexnum; i++)//请输入各顶点信息
{
cin >> G.vexs[i];
}
for (int i = 0; i < G.vexnum; i++)//将邻接矩阵初始化为0
{
for (int j = 0; j < G.vexnum; j++)
{
if (i == j)
G.arcs[i][j] = 0;//环的初始化为0
else
G.arcs[i][j] = INFINITY;//其余的均初始化为无穷
}
}
for (int k = 0; k < G.arcnum; k++)
{
VerTexType v1, v2;
int w;
cout << "请依次输第入" << k + 1 << "条边的两个顶点及权值:";
cin >> v1 >> v2 >> w;
int i = Locatevex(G, v1);//找到顶点在图中边的下标
int j = Locatevex(G, v2);
if (i != -1 && j != -1)//如果能找到对应顶点,对边赋权值
{
G.arcs[i][j] = w;
G.arcs[j][i] = w;
}
}
}
int Min(Closedge c[MVNum], AMGraph G)//从各组边中找到最小边
{
int cost = INFINITY;
int res;
for (int i = 0; i < G.vexnum; i++)
{
if (c[i].lowcost != 0 && c[i].lowcost < cost)//选出不为环的最小值
{
res = i;
cost = c[i].lowcost;
}
}
return res;//返回下标
}
void MiniSpanTree_Prim(AMGraph G, VerTexType v)
{
int k = Locatevex(G, v);
Closedge closedge[MVNum];
for (int i = 0; i < G.vexnum; i++)//对生成顶点进行初始化
{
if (k != i)
{
closedge[i].adjvex = G.vexs[k];//顶点初始化为起始点
closedge[i].lowcost = G.arcs[k][i];//权值初始化为边权值
}
else
{
closedge[i].lowcost = 0;
}
}
for (int i = 0; i < G.vexnum-1; i++)
{
k = Min(closedge, G);
VerTexType u0 = closedge[k].adjvex;//旧顶点
VerTexType v0 = G.vexs[k];//新顶点
cout << "<" << u0 << "," << v0 << ">";//输出新旧点表示边连接
closedge[k].lowcost = 0;
for (int i = 0; i < G.vexnum; i++)
{
if (G.arcs[k][i] < closedge[i].lowcost)//对比新并入点的边与旧边哪个小,若新边小,则替换
{
closedge[i].lowcost = G.arcs[k][i];
closedge[i].adjvex = G.vexs[k];
}
}
}
}
/*********克鲁斯卡尔算法***********/
struct Edge{
int head;//起点
int tail;//终点
ArcType lowcost;//权值
};
struct Amgraph {
VerTexType vexs[MVNum];//顶点信息
Edge edge[MVNum];//边信息结构数组
int arcnum;//边数量
int vexnum;//顶点数量
};
void CreateAMG(Amgraph &G)
{
cout << "请依次输入总顶点数和总边数:";
cin >> G.vexnum >> G.arcnum;
cout << "请输入各顶点信息:" << endl;
for (int i = 0; i < G.vexnum; i++)//请输入各顶点信息
{
cin >> G.vexs[i];
}
cout << "请按权值从小到大输入边对应的起点和终点的下标,以及权值:\n";
for (int k = 0; k < G.arcnum; k++)
{
cout << "第" << k+1 << "条边:";
Edge e;
cin >> e.head >> e.tail >> e.lowcost;
G.edge[k] = e;
}
}
int Find(int *parent, int f)//返回该f点已连接顶点
{
while (parent[f] > 0)
{
f = parent[f];
}
return f;
}
void MiniSpanTree_Kruskal(Amgraph G)
{
int parent[MVNum];//存放最小生成树的顶点
for (int i = 0; i < G.vexnum; i++)
{
parent[i] = 0;
}
int m, n;
for (int i = 0; i < G.arcnum; i++)
{
n = Find(parent, G.edge[i].head);
m = Find(parent, G.edge[i].tail);
if (n != m)//m=n说明有环
{
parent[n] = m;
cout <<"<"<< G.edge[i].head << "," << G.edge[i].tail <<">";//打印边和权值
}
}
}
int main()
{
cout << "/*********邻接矩阵***********/" << endl;
AMGraph G;
CreateUDN(G);
for (int i = 0; i < G.vexnum; i++)
cout << '\t' << "v" << i;
cout << endl;
for (int i = 0; i < G.vexnum; i++)//输出邻接矩阵
{
cout << "v" << i << '\t';
for (int j = 0; j < G.vexnum; j++)
{
cout << G.arcs[i][j] << '\t';
}
cout << endl;
}
VerTexType v;
cout << "请输入生成最小二叉树顶点:";
cin >> v;
cout << "最小生成树如下所示:";
MiniSpanTree_Prim(G, v);
cout << endl;
Amgraph g;
CreateAMG(g);
MiniSpanTree_Kruskal(g);
}