应用场景:还是说建公路,电路网等如何缩短距离,减小成本。
算法过程:
运用了并查集的找祖先以及如何合并->
主要还是看图示,kruskal算法一般会定义结构体:
struct node{
int x;
int y;
int side;//记录边权值
}
bool cmp(node x,node y){
return x.side>y.side;
}
首先看图,我们定义了这个结构体,然后进行排序,然后按最小的,找到最小边权值的两点连接1,3,然后继续寻找第二小的连接4,6,再找就是2连接5,3连接6,注意这边不能3连接4(因为会形成闭环),只要不形成闭环就按该顺序进行操作,操作n-1次即可。最后就走出到了最后一张图的位置,形成了一个最小生成树。
核心代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
int father[N];
int find(int x) {//找祖先
if (x == father[x]) {
return x;
}
return find(father[x]);
}
struct node {
int x, y, r;
}e[N*(N-1)*2];//最多有这么多的结点树上
bool cmp(node a, node b) {//按升序进行排列
return a.r < b.r;
}
int main()
{
int t;//t个测试数据
int n;//n个结点
for (int i = 1; i <= n; i++) {
father[i] = i;
}
for (int i = 1; i <= n; i++) {
cin >> e[i].x >> e[i].y >> e[i].r;
}
sort(e, e + n, cmp);
int sum = 0;
for (int i = 1; i <= n; i++) {
int x = find(e[i].x);
int y = find(e[i].y);
if (x == y)continue;
if (x != y) {//只要祖先不相同就不会形成闭环
sum += e[i].r;
father[x] = y;
}
}
cout << sum << endl;
}
例题:
1584. 连接所有点的最小费用 - 力扣(LeetCode) (leetcode-cn.com)
题目分析:
1.单纯的一道模板题,定义结构体,排序,初始化(每个结点都是自己的祖先)给每个结点赋值,用公式求出边权值。
2.循环输入x,y ,判断祖先是不是一个(是一个就是闭环,排除),不是一个就合并成一个。最后输出边权值,即是最小边权值之和。
代码如下:
class Solution {
public:
struct Node
{
int x, y, r;
}e[1000100];//还是模板定义一个结构体
static int cmp(Node a1, Node a2)
{
return a1.r < a2.r;//升序
}
int father[1010];
int find(int x)//寻找祖先
{
if (x == father[x]) {
return x;
}
return father[x] = find(father[x]);
}
int minCostConnectPoints(vector<vector<int>>& points) {
int cnt = 0;
for (int i = 0; i < points.size(); i++)
{
for (int j = i + 1; j < points.size(); j++)
{
e[cnt].x = i;
e[cnt].y = j;
e[cnt].r = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]);//符合公式求边权值
cnt++;
}
}
sort(e, e + cnt, cmp);//结构体排序
for (int i = 0; i < points.size(); i++) {
father[i] = i;
}//初始化每个结点
int ans = 0;
for (int i = 0; i < cnt; i++)
{
int fx = find(e[i].x);
int fy = find(e[i].y);
if (fx != fy)
{
father[fx] = fy;//合并结点
ans+= e[i].r;
}
}
return ans;
}
};
kraskal算法的基础部分就这些了,还有部分优化部分请看后续。