题目描述
根据输入创建无向网。分别用Prim算法和Kruskal算法构建最小生成树。(假设:输入数据的最小生成树唯一。)
输入
顶点数n
n个顶点
边数m
m条边信息,格式为:顶点1 顶点2 权值
Prim算法的起点v
输出
输出最小生成树的权值之和
对两种算法,按树的生长顺序,输出边信息(Kruskal中边顶点按数组序号升序输出)
#include<iostream>
using namespace std;
struct print { // print变量用于保存待打印的结果
string str1, str2;
int w;
};
struct { //保存邻接边信息
int lowcost;
int adjvex;
}shortEdge[20];
struct Edge { //边的新存储方式
int from, to;
int weight;
};
class Map {
private:
bool* Visit; //记录是否被访问
int** Matrix;
int Vexnum;
int Arcnum;
int* parents; //各个顶点当作各个树,保存每个树的双亲顶点
string* vex;
print* temp; // 待打印的数组
int pos; //prim的起点
int sum = 0; //权值和
Edge edge[20]; //边
int find(string str); // 索引某个顶点
int minEdge(); //查找邻接边的最小边
int findRoot(int n);
void InsertSort(); //插入排序
public:
Map();
~Map();
void Prim();
void Kruskal();
};
int Map::find(string str)
{
for (int i = 0; i < Vexnum; i++)
if (str == vex[i])
return i;
}
Map::Map()// 初始化
{
cin >> Vexnum;
Visit = new bool[Vexnum];
Matrix = new int* [Vexnum];
vex = new string[Vexnum];
parents = new int[Vexnum];
temp = new print[Vexnum];
for (int i = 0; i < Vexnum; i++)
{
cin >> vex[i];
Matrix[i] = new int[Vexnum];
Visit[i] = false;
parents[i] = -1;
for (int j = 0; j < Vexnum; j++)
Matrix[i][j] = 99999;
}
cin >> Arcnum;
for (int i = 0; i < Arcnum; i++)
{
string str1, str2;
int w;
cin >> str1 >> str2 >> w;
Matrix[find(str1)][find(str2)] = w; //prim双向保存边
Matrix[find(str2)][find(str1)] = w;
if (find(str1) > find(str2)) {// kruskal单向保存边
edge[i].from = find(str2);
edge[i].to = find(str1);
}
else {
edge[i].from = find(str1);
edge[i].to = find(str2);
}
edge[i].weight = w;
}
string str;
cin >> str;
pos = find(str);
}
int Map::minEdge()
{
int min = 9999, j = 0;
for (int i = 0; i < Vexnum; i++) {
if (shortEdge[i].lowcost && shortEdge[i].lowcost < min) {
min = shortEdge[i].lowcost;
j = i;
}
}
return j;
}
void Map::InsertSort()
{
int j;
Edge temp;
for (int i = 1; i < Arcnum; i++) {
if (edge[i].weight < edge[i - 1].weight) {
temp = edge[i];
for (j = i - 1; j >= 0 && edge[j].weight > temp.weight; --j) {
edge[j + 1] = edge[j];
}
edge[j + 1] = temp;
}
}
}
void Map::Prim()
{
for (int i = 0; i < Vexnum; i++) {// 起点的邻接边信息
shortEdge[i].lowcost = Matrix[pos][i];
shortEdge[i].adjvex = pos;
}
shortEdge[pos].lowcost = 0; //置0表已纳入树
Visit[pos] = true;
for (int i = 0; i < Vexnum - 1; i++) {
int k = minEdge(); //最小邻接边位置
temp[i].str1 = vex[shortEdge[k].adjvex];
temp[i].str2 = vex[k];// 先保存再打印
temp[i].w = shortEdge[k].lowcost;
sum += shortEdge[k].lowcost;
shortEdge[k].lowcost = 0;//置0表已纳入树
for (int j = 0; j < Vexnum; j++) { //在矩阵第k行找更短边,更新shortedge
if (Matrix[k][j] < shortEdge[j].lowcost) {
shortEdge[j].lowcost = Matrix[k][j];
shortEdge[j].adjvex = k;
}
}
}
cout << sum << endl;
cout << "prim:" << endl;
for (int i = 0; i < Vexnum - 1; i++) {
cout << temp[i].str1 << ' ' << temp[i].str2 << ' '
<< temp[i].w << endl;
}
}
int Map::findRoot(int n)
{
int t = n;
while (parents[t] > -1)
t = parents[t];
return t;
}
void Map::Kruskal()
{
cout << "kruskal:" << endl;
InsertSort();
for (int num = 0, i = 0; i < Arcnum; i++) {
int vex1 = findRoot(edge[i].from); // 找出某条边两端的根结点
int vex2 = findRoot(edge[i].to);
if (vex1 != vex2) {//根节点不同表示加入该边不会形成环
cout << vex[edge[i].from] << ' '
<< vex[edge[i].to] << ' '
<< edge[i].weight << endl;
parents[vex2] = vex1;
num++;
if (num == Vexnum - 1)
return;
}
}
}
Map::~Map()
{
delete[]vex;
delete[]Visit;
for (int i = 0; i < Vexnum; i++)
delete Matrix[i];
delete[]Matrix;
}
int main()
{
Map map;
map.Prim();
map.Kruskal();
system("pause");
return 0;
}