杨乐 2008283046

水一波基础算法。。。。
最小生成树Kruskal算法
该算法涉及到了快速排序算法、并查集,通过快速排序,选择最短边,并查集筛选未相连的边,然后进行边的链接。
快速排序
快速排序算法通过多次比较和交换实现排序,大致流程如下:
- 定义一个tmp作为基准数,通过该数把数组分成:比其大和比其小的左右两部分,该值的设定可以为随机值、最左边、最右边和中间,设情况而定。
- 将大于或等于基准数的数swap到数组右边,小于基准数的数swap到数组的左边。
- 则使用递归方法,左边和右边的数据可以独立排序,每次递归都可设置新的tmp基准数,当左、右两个部分各数排序完成后,整个数组的排序也就完成了。
并查集
并查集是一种数据结构,用于处理一些不相交集合的合并及查询问题,主要操作为初始化、查找和合并。
初始化操作,每个人都是自己圈子里的,即 fat[a] = a;
合并操作,假如a是b的圈子里的,则记为 fat[b] = a;
查询操作,查询a是不是b圈子里的,return x!=fat[x]?find(fat[x]) : x;
所需的时间复杂度很低。
Kruskal算法实现
Kruskal算法是基于贪心的思想得到的。首先我们把所有的边Edge按照边长先从小到大排列,接着按照顺序选取每条边,如果这条边和另一条边相连后,不会形成一个闭环,那么就将它们合并,直到选择的边数等于端点数减一。至于怎么选择边,那么这里我们就可以用到一个工具——-并查集。换而言之,Kruskal算法就是基于并查集的贪心算法。
/**************************
* 2008283046
* 杨乐
***************************/
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <math.h>
using namespace std;
#define N 105
struct Edge{
int u, v;
int value;
}e[N];
int fat[N]; // 关系数组
int sum;
int n, m;
void swp(int &x, int &y){
int tmp = x;x = y;y = tmp; // swap交换两个数
}
void quickSort(Edge a[], int left, int right){
if(left >= right) return;
// 分支界限,当left大于right时返回
int i = left;
int j = right;
int tmp = a[i].value; // 取最左边数当基准数
while(i != j){
while(tmp <= a[j].value && i < j) j --;
// 从右边查看第一个小于tmp的值
while(tmp >= a[i].value && i < j) i ++;
// 从左边查看第一个大于tmp的值
if(i != j) swap(a[i], a[j]);
// 交换找到的值
}
swap(a[left], a[i]);
// 基准数归位
quickSort(a, left, i - 1); // 分治法处理左边
quickSort(a, i + 1, right);// 分治法处理右边
}
int find(int x){
while(x!=fat[x]){ //找到自身停止
x=fat[x];
}
return x;
}
bool islink(int x,int y){
int i = find(x);
int j = find(y);
if(i != j){ //查看两者是否有关联
fat[i] = j; //无关联就将其关联起来
return true;
}
else return false;
}
void input(){
freopen("data.txt", "r", stdin);
freopen("out.txt", "w", stdout);
cout << "请依次输入点和边的数量以及边: " << endl;
cin >> n >> m;
for(int i = 0; i < n; i++){
fat[i] = i;
}
for(int i = 0;i < m; i++){
cin >> e[i].u >> e[i].v >> e[i].value;
}
quickSort(e, 0, m - 1);
}
int main(){
int count = 0;
sum = 0;
input();
for(int i = 0; i < m; i++){
if(islink(e[i].u, e[i].v)){ // 通过并查集的关系选边
sum += e[i].value;
printf("连接 %d, %d.\n", e[i].u, e[i].v, e[i].value);
count ++;
}
if(count == m - 1) break;
}
cout << "最小生成树的长度是: " << sum << endl;
return 0;
}
/*
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
*/
本文详细介绍了Kruskal算法,一种用于求解图的最小生成树的问题。内容包括算法的基本思想、快速排序、并查集的原理,以及如何结合这些工具实现Kruskal算法。此外,还提供了C++代码示例,帮助读者理解算法的实现过程。
2007

被折叠的 条评论
为什么被折叠?



