问题描述
在给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边,而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集且为无循环图,使得w(T) 最小,则此 T 为 G 的最小生成树。
(一) 克鲁斯卡尔算法:
对边进行排序,从最小的边开始进行贪心,每个点视为一个集合,若是边两端不是同一个集合之中,将两个集合合并。直到剩下一个集合,即为最小生成树。
(二) 普里姆算法:
选取一点为最开始的集合,寻找距离这个集合最近的点,加入集合。
设计
[核心伪代码]
最小生成树:
(一) 克鲁斯卡尔算法:
建立结构体数组A,保存边和他的两个端点;n
输入图;
将数组A自小到大排序;logn
建立数组B并置每位等于自己,作为各个集合的元素;
遍历A中的边,若是双边在同一集合则不操作,否则合并两个集合,输出边;n
(二) 普里姆算法:
建立二维数组A以保存图;
输入图;
建立数组B置所有位为0;n
遍历第一个点连接的边,标记最小的并把B数组中此点和点1置1,输出边;<n
循环{
If(B全为1)break;
遍历所有标记为1的点,标记同他们相连的最近为0的点,置其为1, 输出边;
};<n* n*(n-1)
分析
在边少的情况下kruskal的效率应该是高于prim的
源码
[github源码地址]
暂无git;
kruskal:
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
struct edge
{
int a, b, len;
};
int cmp(const void *a, const void *b)
{
int c = (*(edge *)a).len, d = (*(edge *)b).len;
return c-d;
}
int B[10];
int find(int a){
return B[a] == a ? a : B[a]=find(B[a]);
}
int main()
{
ifstream in;
in.open("input.txt");
int m, n;
in >> m >> n;
struct edge A[15];
//初始化数组
for (int i = 0; i < m; i++)
{
B[i] = i;
}
//存图
for (int i = 0; i < n; i++)
{
char a, b;
int c;
in >> a >> b >> c;
a -= 'a';
b -= 'a';
A[i].a = a;
A[i].b = b;
A[i].len = c;
}
qsort(A, n, sizeof(A[0]), cmp);
for (int i = 0; i < n; i++)
{
if (find(A[i].a)!=find(A[i].b)){
B[find(A[i].b)] = find(A[i].a);
cout << (char)(A[i].b+'a') << "--" << (char)(A[i].a+'a') << " " << A[i].len << endl;
}
}
in.close();
}
prim:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
ifstream in;
in.open("input.txt");
int A[10][10], m, n, B[10];
in >> m >> n;
//初始化数组
for (int i = 0; i < m; i++)
{
B[i] = 0;
for (int j = 0; j <= i; j++)
{
A[i][j] = A[j][i] = INT32_MAX;
}
}
//存图
for (int i = 0; i < n; i++)
{
char a, b;
int c;
in >> a >> b >> c;
a -= 'a';
b -= 'a';
A[a][b] = A[b][a] = c;
}
//处理第一个点
int date = INT32_MAX, flag = 0;
for (int i = 0; i < m; i++)
{
if (A[0][i] < date)
{
flag = i;
date = A[0][i];
}
}
cout << 'a' << "--" << (char)(flag + 'a') << " "<<date << endl;
B[0] = B[flag] = 1;
while (1)
{
date = INT32_MAX, flag = 0;
int flag2 = 0;
int break_date = 0;
for (int i = 0; i < m; i++)
{
if (B[i] == 0)
break_date = 1;
else
{
for (int j = 0; j < m; j++)
{
if (!B[j])
{
if (A[i][j] < date)
{
flag = i;
flag2 = j;
date = A[i][j];
}
}
}
}
}
if (!break_date)
break;
B[flag2] = 1;
cout << (char)(flag + 'a') << "--" << (char)(flag2 + 'a') <<" "<< date << endl;
}
in.close();
}