Sollin算法可以看作是Kruskal算法和Prim算法的综合

基本思想是:

1. 从所有节点都孤立的森林开始,通过合并树来得到最小生成树

2. 每次合并树的边都是用最小权重的割边





程序具体实现思路:

初始化,update所有点(update函数只在开始处使用一次,以后就不用了)(update的具体操作类似于prim算法里的update)

循环一:找最小割边(FindMin)

循环二:1.根据每棵树都的最小割边进行合并

2.V[gen]中删除S[gen_other]中的所有元素

3.S[gen]中增加S[gen_other]中的所有元素

4.更新d值,在V[gen]中比较d[gen][i]和d[gen_other][i],取小值



和prim算法相比,这里的V和S都是有维度的,还有d也从一维变成了二维,增加的维度是对每棵树的标示





我用C++实现的Sollin算法源程序如下:

(1)common.h 主要是程序的头文件

(2)sollin.cpp 图的创建和算法启动点

(3)resources.h 图类、边类、点类,其中图类中包含了整个程序的核心部分

(1)common.h

#define _COMMON_H_
#include <map>
#include <vector>
#include <list>
#include <set>
#include <cstdio>
using namespace std;
#include <iostream>
#include <stdio.h>
#include <algorithm>
#define INF 10000
#define N 5
#endif

(2)sollin.cpp

#include "resources.h"

CEdge::CEdge(int a, int b, int c, int d){
tail=a;
head=b;
weight=c;
capacity=d;
} CEdge::CEdge(int a, int b, int c){
head=b;
tail=a;
weight=c;
} CEdge::CEdge(CEdge & x){
tail=x.getTail();
head=x.getHead();
weight=x.getWeight();
capacity=x.getCap();
} CGraph::CGraph(list<CEdge*> listEdge){
IncidentList=listEdge;
numVertex=N;
numEdge=listEdge.size();
} void main()
{
list<CEdge*> listEdge; CEdge* e1= new CEdge(1,2,35,10);
CEdge* e2= new CEdge(1,3,40,10);
CEdge* e3= new CEdge(2,3,25,10);
CEdge* e4= new CEdge(2,4,10,10);
CEdge* e5= new CEdge(3,4,20,10);
CEdge* e6= new CEdge(3,5,15,10);
CEdge* e7= new CEdge(4,5,30,10); CEdge* e8= new CEdge(2,1,35,10);
CEdge* e9= new CEdge(3,1,40,10);
CEdge* e10= new CEdge(3,2,25,10);
CEdge* e11= new CEdge(4,2,10,10);
CEdge* e12= new CEdge(4,3,20,10);
CEdge* e13= new CEdge(5,3,15,10);
CEdge* e14= new CEdge(5,4,30,10); listEdge.push_back(e1);
listEdge.push_back(e2);
listEdge.push_back(e3);
listEdge.push_back(e4);
listEdge.push_back(e5);
listEdge.push_back(e6);
listEdge.push_back(e7); listEdge.push_back(e8);
listEdge.push_back(e9);
listEdge.push_back(e10);
listEdge.push_back(e11);
listEdge.push_back(e12);
listEdge.push_back(e13);
listEdge.push_back(e14); CGraph g(listEdge);
g.p3();
g.p4();
g.solin();
getchar();
}

(3)resources.h

#include "common.h"

int set1[110]={0};

int FindSet(int x)
{
if(x==set1[x])
return x;
else
return set1[x]=FindSet(set1[x]);
} void UnionSet(int x, int y)
{
int fx=FindSet(x);
int fy=FindSet(y);
set1[fy]=fx;
} class CEdge{
private:
int tail, head;
int weight, capacity;
public:
CEdge(int a, int b, int c, int d);
CEdge(int a, int b, int c);
CEdge(CEdge &x);
int getHead(){return head;}
int getTail(){return tail;}
int getWeight(){return weight;}
int getCap(){return capacity;} }; bool cmp(CEdge* a, CEdge* b)
{
if(a->getWeight()<b->getWeight())
return 1;
else
return 0;
} class CGraph{
private:
int numVertex;
int numEdge;
list<CEdge*> IncidentList;
public:
CGraph(char* inputFile);
CGraph(list<CEdge*> listEdge);
CGraph(CGraph &);
map<int,list<CEdge*>> nelist;
vector<vector<CEdge*>> adjmatrix;
int d[N+10][N+10];
set<int> S[N+10];//被永久标记的点集
set<int> V[N+10];//初始点集 int getNumVertex(){
return numVertex;
}
int getNumEdge(){
return numEdge;
}
void p3(){
list<CEdge*>::iterator it,iend;
iend=IncidentList.end();
CEdge* emptyedge=new CEdge(-1,-1,-1,-1);
for(int i=0;i<=numVertex;i++)
{
vector<CEdge*> vec;
for(int j=0;j<=numVertex;j++)
{
vec.push_back(emptyedge);
}
adjmatrix.push_back(vec);
}
for(it=IncidentList.begin();it!=iend;it++){
adjmatrix[(*it)->getTail()][(*it)->getHead()] = *it ; }
} void p4(){
list<CEdge*>::iterator it,iend;
iend=IncidentList.end(); for(it=IncidentList.begin();it!=iend;it++)
nelist[(*it)->getTail()].push_back(*it); list<CEdge*>::iterator it2,iend2;
iend2=nelist[3].end();
} void Update(int k, int i){
list<CEdge*>::iterator it,iend;
it=nelist[i].begin();
iend=nelist[i].end();
for(;it!=iend;it++)
if((*it)->getWeight()<d[k][(*it)->getHead()]){
d[k][(*it)->getHead()]=(*it)->getWeight();
}
} int FindMin(int k){
set<int>::iterator vi,vend;
vend=V[k].end();
int mini=10000000;
int loc=0;
for(vi=V[k].begin();vi!=vend;vi++)
if(mini>=d[k][*vi])
{mini=d[k][*vi];loc=*vi;}
return loc;
} void solin(){
printf("sollin:\n");
for(int i=1;i<=N;i++)
set1[i]=i;
list<CEdge*> T;
int e[N+10];
//初始化操作
int j,k;
for(k=1;k<=N;k++)
for(j=1;j<=N;j++){
V[k].insert(j);
d[k][j]=INF;
} for(k=1;k<=N;k++){
S[k].insert(k);
V[k].erase(k);
d[k][k]=0;
Update(k,k);
} while(T.size()<(N-1))
{
for(int i=1;i<=N;i++)
{
if(i!=FindSet(i)) continue;
e[i]=FindMin(i);
}//1 for 查找N(k)与V–N(k)之间的最小割边 for(int i=1;i<=N;i++)
{
if(i!=FindSet(i)) continue;
if(FindSet(e[i])!=FindSet(i))
{
UnionSet(e[i],i);//合并树
//V[gen]中删除S[gen_other]中的所有元素
//S[gen]中增加S[gen_other]中的所有元素
int gen,gen_other;
gen=FindSet(i);
if(gen==i) gen_other=e[i];
else gen_other=i;
set<int>::iterator it,iend;
iend=S[gen_other].end();
for(it=S[gen_other].begin();it!=iend;it++){
V[gen].erase(*it);
S[gen].insert(*it);
}
//更新d值,在V[gen]中比较d[gen][i]和d[gen_other][i],取小值
iend=V[gen].end();
for(it=V[gen].begin();it!=iend;it++)
if(d[gen][*it]>d[gen_other][*it])
d[gen][*it]=d[gen_other][*it];
T.push_back(adjmatrix[e[i]][i]);
printf("%d---%d\n",e[i],i);
}
}//2 for 合并两棵树
}//while循环
}//sollin算法
};//graph类

Sollin算法的C++实现 BY gremount的更多相关文章

  1. Borůvka (Sollin) 算法求 MST 最小生成树

    基本思路: 用定点数组记录每个子树的最近邻居. 对于每一条边进行处理: 如果这条边连成的两个顶点同属于一个集合,则不处理,否则检测这条边连接的两个子树,如果是连接这两个子树的最小边,则更新 (合并). ...

  2. ACM主要算法

    ACM主要算法ACM主要算法介绍 初期篇 一.基本算法(1)枚举(poj1753, poj2965)(2)贪心(poj1328, poj2109, poj2586)(3)递归和分治法(4)递推(5)构 ...

  3. ACM常用算法

    数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...

  4. ACM需要掌握算法

    数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...

  5. ACM用到的算法。先做个笔记,记一下

    ACM 所有算法 数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 ...

  6. ACM算法目录

    数据结构 栈,队列,链表 •哈希表,哈希数组 •堆,优先队列 双端队列 可并堆 左偏堆 •二叉查找树 Treap 伸展树 •并查集 集合计数问题 二分图的识别 •平衡二叉树 •二叉排序树 •线段树 一 ...

  7. ACM技能表

    看看就好了(滑稽) 数据结构 栈 栈 单调栈 队列 一般队列 优先队列/单调队列 循环队列 双端队列 链表 一般链表 循环链表 双向链表 块状链表 十字链表 邻接表/邻接矩阵 邻接表 邻接多重表 Ha ...

  8. Radix Heap ---Dijkstra算法的优化 BY Gremount

    Radix Heap 算法是在Dijkstra的Dial实现的基础上,通过减少对桶的使用,来优化算法的时间复杂度: Dial 时间复杂度是O(m+nC)     -------C是最长的链路 Radi ...

  9. ACM算法整理(不断补充ing)

    动态规划 1.背包问题 (1)01背包 ,n) DFR(v,V,C[i]) F[v]=max(F[v],F[v-C[i]]+W[i]); } //初始化时 //若背包不一定装满F全初始化为0 //若装 ...

随机推荐

  1. JavaScript内置一些方法的实现原理--Object.freeze()、instanceof

    const定义的常量,一般是不能修改的. 比如: const TIME_OUT = 10000; 但是当值为引用类型值时,还是可以操作对象,扩展或修改对象属性.方法等等. 以下演示代码的操作是不会报错 ...

  2. Java 之 字符输入流[Reader]

    一.字符输入流 java.io.Reader 抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中. 它定义了字符输入流的基本共性功能方法. public void close() :关 ...

  3. S5PV210 PWM

    定时器PWM输出 原理图 GPD0CON, R/W, Address = 0xE020_00A0 CON, R/W, Address = 0xE250_0008 相关文章:http://blog.cs ...

  4. centos7 安装jdk及mysql8

    安装jdk 1.上传压缩包:通过SSH上传jdk压缩包,比如上传至/usr/local/java目录下 2.解压压缩包:利用命令解压压缩包 tar -zxvf  jdk-11.0.5_linux-x6 ...

  5. awk初级教程

    参考:sed & awk 概述 sed & awk指令组成 与sed区别 尽管awk指令与sed指令的结构相同,都由模式和过程两部分组成,但过程本身有很大不同. awk看上去不像编辑器 ...

  6. kvm虚拟机控制台登录配置

    vm虚拟机能否像xen虚拟机一样通过virsh console 一样采用字符界面进行linux虚拟机控制台呢,答案是肯定的,默认情况下该命令是不起作用的,需要修改相关文件才能实现. 本文出自:http ...

  7. 切换Python环境 linux终端命令行

    切换Python环境 conda info -e // 查看有什么环境 source activate env //切换环境 linux终端分屏 terminator  https://www.jia ...

  8. 从OkHttp的源码来看 HTTP

    先来了解一下OkHttp的历史,最早是square公司觉得Android给的HttpClient这块的库不太好用,于是乎做了一层包装,再后来他们包装的这个库被Android官方给收回去了,而Andro ...

  9. linux网络编程之socket编程(十)

    今天继续socket编程的学习,最近晚上睡觉都没有发热,没有暖气的日子还是种煎熬,快乐的十一也已经走来,幸福有暖气的日子也快啦,好了,回到正题~ ①close终止了数据传送的两个方向. ②shutdo ...

  10. Gym - 102346D Denouncing Mafia 取k叶子节点使叶子到根覆盖节点数最大

    给你一棵树 你可以取K条链 一条链为根到叶子的路径 问你K条链最多覆盖树上多少个节点 贪心的做 肯定是每次取最长链 但是取完最长链 一颗树就会变为若干个森林 我们要维护当前所有森林里的最长链 ans数 ...