题目描述
给出一个矩阵,要求以矩阵方式单步输出最小生成树生成过程。要求先输出Prim生成过程(以点0作为起始点),再输出Kruskal,每个矩阵输出后换行。注意,题中矩阵表示无向图
输入
结点数
矩阵
输出
Prim:
矩阵输出
Kruskal:
矩阵输出
样例输入
3
0 1 3
1 0 2
3 2 0
样例输出
Prim:
0 0 0
0 0 0
0 0 0
0 1 0
1 0 0
0 0 0
0 1 0
1 0 2
0 2 0
Kruskal:
0 0 0
0 0 0
0 0 0
0 1 0
1 0 0
0 0 0
0 1 0
1 0 2
0 2 0
这个题目,博主实在不会(太拉跨了),我整理了一下这个博主的(感谢大佬)点击这里,还是稍有不同,希望能有大佬教教孩子,先谢过了
#include <iostream>
#include <queue>
#include <map>
using namespace std;
int num;
int** edge;
class DisjointSet
{
private:
int* parent;
public:
DisjointSet(int n = 100)
{
parent = new int[n];
for (int i = 0; i < n; i++)
{
parent[i] = i;
}
}
~DisjointSet()
{
delete[] parent;
}
int Find(int u)
{
return parent[u] == u ? u : Find(parent[u]);
}
void Merge(int v, int u)
{
parent[Find(v)] = Find(u);
}
bool Same(int x1, int x2)
{
return Find(x1) == Find(x2);
}
};
struct Edge {
int from;
int to;
int cost;
Edge()
{
from = -1;
to = -1;
cost = 0;
}
};
struct tmp
{
bool operator()(const Edge a, const Edge b)const
{
//优先比较权重,若权重相同就规定按照起始边排序
if (a.cost == b.cost)
return a.from >= b.from;
return a.cost >= b.cost;
}
};
void Print(int arr[100][100]) {
for (int i = 0; i < num; i++)
{
for (int j = 0; j < num; j++)
cout << arr[i][j] << " ";
cout << endl;
}
cout << endl;
}
void Prim()
{
int arr[100][100] = { 0 };
//创建最小堆同理
priority_queue<Edge, vector<Edge>, tmp> minHeap;
//创建布尔数组用于判断该点是否遍历
bool* point = new bool[num];
//初始化
for (int i = 0; i < num; i++)
point[i] = false;
point[0] = true;
int count = 1;
int current = 0;
Edge newedge;
//输出空白的邻接矩阵,和算法无关纯属题目要求
Print(arr);
do
{
for (int i = 0; i < num; i++)//把某个结点的全部邻点放入最小堆中
{
if (edge[current][i] != 0)//确保这个点跟 “某个节点” 是相连接的
{
if (point[i] == false)//确报这个点没有走过
{
newedge.from = current;
newedge.to = i;
newedge.cost = edge[current][i];
minHeap.push(newedge);
}
}
}
while (!minHeap.empty() && count < num)//从最小堆里提取元素
{
newedge = minHeap.top();//得到权重最小的边
minHeap.pop();//出队
if (point[newedge.to] == false)//确保这个节点没有使用过
{
arr[newedge.from][newedge.to] = newedge.cost;//对辅助数组进行更新
arr[newedge.to][newedge.from] = newedge.cost;//
current = newedge.to;//对结点进行更新,
point[current] = true;
count++;
Print(arr);
break;
}
}
} while (count < num);
}
void Kruskal()
{
int arr[100][100] = { 0 };
Edge* e = new Edge[1000];
//用以下操作来记录邻接矩阵中的每一条边,存放在e节点数组中
int t = 0;
for (int i = 1; i < num; i++) {
for (int j = 0; j < i; j++) {
if (edge[i][j] != 0)
{
e[t].from = j;
e[t].to = i;
e[t].cost = edge[i][j];
t++;
}
}
}
DisjointSet dis(num);
//创建最小堆,里面的cmp比较函数在上面板块中给出
priority_queue<Edge, vector<Edge>, tmp> minHeap;
for (int i = 0; i < t; i++)
minHeap.push(e[i]);
Print(arr);
int count = 1;
while (count < num)
{
//取最小权值边
Edge minedge = minHeap.top();
minHeap.pop();
int a, b, c;
a = minedge.from;
b = minedge.to;
c = minedge.cost;
//判断边的两顶点是否在同一个并查集下
if (!dis.Same(a, b))
{
//不是则合并,并连上线输出一次
dis.Merge(a, b);
arr[a][b] = c;
arr[b][a] = c;
count++;
Print(arr);
}
}
}
int main() {
cin >> num;
edge = new int* [num];
for (int i = 0; i < num; i++)
edge[i] = new int[num];
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
cin >> edge[i][j];
}
}
cout << "Prim:" << endl;
Prim();
cout << "Kruskal:" << endl;
Kruskal();
}