Sollin算法的C++实现 BY gremount
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的更多相关文章
- Borůvka (Sollin) 算法求 MST 最小生成树
基本思路: 用定点数组记录每个子树的最近邻居. 对于每一条边进行处理: 如果这条边连成的两个顶点同属于一个集合,则不处理,否则检测这条边连接的两个子树,如果是连接这两个子树的最小边,则更新 (合并). ...
- ACM主要算法
ACM主要算法ACM主要算法介绍 初期篇 一.基本算法(1)枚举(poj1753, poj2965)(2)贪心(poj1328, poj2109, poj2586)(3)递归和分治法(4)递推(5)构 ...
- ACM常用算法
数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...
- ACM需要掌握算法
数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...
- ACM用到的算法。先做个笔记,记一下
ACM 所有算法 数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 ...
- ACM算法目录
数据结构 栈,队列,链表 •哈希表,哈希数组 •堆,优先队列 双端队列 可并堆 左偏堆 •二叉查找树 Treap 伸展树 •并查集 集合计数问题 二分图的识别 •平衡二叉树 •二叉排序树 •线段树 一 ...
- ACM技能表
看看就好了(滑稽) 数据结构 栈 栈 单调栈 队列 一般队列 优先队列/单调队列 循环队列 双端队列 链表 一般链表 循环链表 双向链表 块状链表 十字链表 邻接表/邻接矩阵 邻接表 邻接多重表 Ha ...
- Radix Heap ---Dijkstra算法的优化 BY Gremount
Radix Heap 算法是在Dijkstra的Dial实现的基础上,通过减少对桶的使用,来优化算法的时间复杂度: Dial 时间复杂度是O(m+nC) -------C是最长的链路 Radi ...
- ACM算法整理(不断补充ing)
动态规划 1.背包问题 (1)01背包 ,n) DFR(v,V,C[i]) F[v]=max(F[v],F[v-C[i]]+W[i]); } //初始化时 //若背包不一定装满F全初始化为0 //若装 ...
随机推荐
- JavaScript内置一些方法的实现原理--Object.freeze()、instanceof
const定义的常量,一般是不能修改的. 比如: const TIME_OUT = 10000; 但是当值为引用类型值时,还是可以操作对象,扩展或修改对象属性.方法等等. 以下演示代码的操作是不会报错 ...
- Java 之 字符输入流[Reader]
一.字符输入流 java.io.Reader 抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中. 它定义了字符输入流的基本共性功能方法. public void close() :关 ...
- S5PV210 PWM
定时器PWM输出 原理图 GPD0CON, R/W, Address = 0xE020_00A0 CON, R/W, Address = 0xE250_0008 相关文章:http://blog.cs ...
- centos7 安装jdk及mysql8
安装jdk 1.上传压缩包:通过SSH上传jdk压缩包,比如上传至/usr/local/java目录下 2.解压压缩包:利用命令解压压缩包 tar -zxvf jdk-11.0.5_linux-x6 ...
- awk初级教程
参考:sed & awk 概述 sed & awk指令组成 与sed区别 尽管awk指令与sed指令的结构相同,都由模式和过程两部分组成,但过程本身有很大不同. awk看上去不像编辑器 ...
- kvm虚拟机控制台登录配置
vm虚拟机能否像xen虚拟机一样通过virsh console 一样采用字符界面进行linux虚拟机控制台呢,答案是肯定的,默认情况下该命令是不起作用的,需要修改相关文件才能实现. 本文出自:http ...
- 切换Python环境 linux终端命令行
切换Python环境 conda info -e // 查看有什么环境 source activate env //切换环境 linux终端分屏 terminator https://www.jia ...
- 从OkHttp的源码来看 HTTP
先来了解一下OkHttp的历史,最早是square公司觉得Android给的HttpClient这块的库不太好用,于是乎做了一层包装,再后来他们包装的这个库被Android官方给收回去了,而Andro ...
- linux网络编程之socket编程(十)
今天继续socket编程的学习,最近晚上睡觉都没有发热,没有暖气的日子还是种煎熬,快乐的十一也已经走来,幸福有暖气的日子也快啦,好了,回到正题~ ①close终止了数据传送的两个方向. ②shutdo ...
- Gym - 102346D Denouncing Mafia 取k叶子节点使叶子到根覆盖节点数最大
给你一棵树 你可以取K条链 一条链为根到叶子的路径 问你K条链最多覆盖树上多少个节点 贪心的做 肯定是每次取最长链 但是取完最长链 一颗树就会变为若干个森林 我们要维护当前所有森林里的最长链 ans数 ...