最小生成树之算法记录【prime算法+Kruskal算法】【模板】
首先说一下什么是树:
1、只含一个根节点
2、任意两个节点之间只能有一条或者没有线相连
3、任意两个节点之间都可以通过别的节点间接相连
4、除了根节点没一个节点都只有唯一的一个父节点
5、也有可能是空树(不含任何节点)
最小生成树就是:
在所有数据满足是一棵树的情况下一条将所有节点都连接起来且长度最短的一条路(因为任意两个节点之间有权值
(相连的两点之间权值为一个具体的数,不相连的两个点之间权值为无穷大))
下面介绍通用的求最小生成树的两种算法:
ps:这里用的两种算法都是用邻接矩阵实现适合点稠密型数据或者数据较小的情况:
(1)prime算法:
/*
* 数组tree[]用来记录最小生成树的节点
* 数组lowdis[]记录从起点到其余所有点的距离并不断更新
* 数组map[][]记录所有数据两点之间的距离
* point是所有节点的数目,begin是起点
* mindis是最小生成树的长度
*/
void prime()
{
int i,j,min,mindis=0,next;
memset(tree,0,sizeof(tree));
for(i=1;i<=point;i++)
{
lowdis[i]=map[begin][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
}
tree[begin]=1;//标记起点(即最小生成树中的点)
for(i=1;i<point;i++)
{
min=INF;
for(j=1;j<=point;j++)
{
if(!tree[j]&&min>lowdis[j])
{
min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
next=j;
}
}
mindis+=min;//记录下整条最小树的长度
tree[next]=1;
for(j=1;j<=point;j++)
{
if(!tree[j]&&lowdis[j]>map[next][j])
lowdis[j]=map[next][j];//更新lowdis[]数组
}
}
printf("%d\n",mindis);
}
kruskal算法:
此算法的核心就是在并查集(并查集知识请看 知识小总结记录分类中的并查集(http://www.cnblogs.com/tonghao/p/4442821.html))的基础上对两点之间距离进行排序:
find()函数用来查找根节点
int find(int father)//查找根节点
{
int t;
int children=father;
while(father!=set[father])
father=set[father];
while(fa!=set[children])
{
t=set[children];
set[children]=father;
children=t;
}
return father;
}
mix函数用来合并两个节点,使两个节点的父节点相同
void mix(int x,int y)//将两个点合并(即另两点根节点相同)
{
int fx;
int fy;
fx=find(x);
fy=find(y);
if(fx!=fy)
set[fx]=fy;
}
利用结构体排序:
struct record
{
int begin;//记录两个点中的一个
int end;//记录两个点中的一个
int dis;//记录两点之间距离
}num[MAX];
bool cmp(int a,int b)
{
return a.dis<b.dis;//对两点之间距离进行从大到小的排序
}
用一个题来实现上述两个算法:
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
prime算法:
#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f
int lowcost[110];//此数组用来记录第j个节点到其余节点最少花费
int map[110][110];//用来记录第i个节点到其余n-1个节点的距离
int visit[110];//用来记录最小生成树中的节点
int city;
void prime()
{
int min,i,j,next,mincost=0;
memset(visit,0,sizeof(visit));//给最小生成树数组清零
for(i=1;i<=city;i++)
{
lowcost[i]=map[1][i];//初始化lowcost数组为第1个节点到剩下所有节点的距离
}
visit[1]=1;//选择第一个点为最小生成树的起点
for(i=1;i<city;i++)
{
min=INF;
for(j=1;j<=city;j++)
{
if(!visit[j]&&min>lowcost[j])//如果第j个点不是最小生成树中的点并且其花费小于min
{
min=lowcost[j];
next=j;//记录下此时最小的位置节点
}
}
if(min==INF)
{
printf("?\n");
return ;
}
mincost+=min;//将最小生成树中所有权值相加
visit[next]=1;//next点加入最小生成树
for(j=1;j<=city;j++)
{
if(!visit[j]&&lowcost[j]>map[next][j])//如果第j点不是最小生成树中的点并且此点处权值大于第next点到j点的权值
{
lowcost[j]=map[next][j]; //更新lowcost数组
}
}
}
printf("%d\n",mincost);
}
int main()
{
int road;
int j,i,x,y,c;
while(scanf("%d%d",&road,&city)&&road!=0)
{
memset(map,INF,sizeof(map));//初始化数组map为无穷大
while(road--)
{
scanf("%d%d%d",&x,&y,&c);
map[x][y]=map[y][x]=c;//城市x到y的花费==城市y到想的花费
}
prime();
}
return 0;
}
kruskal算法:
/*
* set[]数组用来存放根节点
* find()函数用来查找根节点
* mix()函数用来将两个点合并(即使其父节点相同)
*/
#include<stdio.h>
#include<algorithm>
using namespace std;
int set[110];
struct record
{
int beg;
int end;
int money;
}s[11000];
int find(int fa) //查找根节点
{
int ch=fa;
int t;
while(fa!=set[fa])
fa=set[fa];
while(ch!=fa)
{
t=set[ch];
set[ch]=fa;
ch=t;
}
return fa;
}
void mix(int x,int y) //合并两点
{
int fx,fy;
fx=find(x);
fy=find(y);
if(fx!=fy)
set[fx]=fy;
}
bool cmp(record a,record b)
{
return a.money<b.money; //对价格进行排序
}
int main()
{
int city,road,n,m,j,i,sum;
while(scanf("%d",&road)&&road!=0)
{
scanf("%d",&city);
for(i=0;i<road;i++)
{
scanf("%d%d%d",&s[i].beg,&s[i].end,&s[i].money);
}
for(i=1;i<=city;i++)
set[i]=i; //初始化set[]数组
sort(s,s+road,cmp);
sum=0;
for(i=0;i<road;i++) //这个地方可能不好理解 我在下面作出解释
{
if(find(s[i].beg)!=find(s[i].end)) //当两点没有连接时才可以连接两点
{
mix(s[i].beg,s[i].end); //因为已经按照价钱从高到低排序好了所以可以找到
sum+=s[i].money; //在两个点 未相连的情况下的最小权值并将其相连
}
}
j=0;
for(i=1;i<=city;i++)
{
if(set[i]==i)
j++;
if(j>1)
break;
}
if(j>1) //如果根节点不只一个则证明此组数据不是一棵树
printf("?\n");
else
printf("%d\n",sum);
}
return 0;
}
这里对上面代码中所说的地方作出解释:
/*
*例如给出一组数据
*3 3
*1 2 1
*2 3 4
*1 3 2
*我们按照价钱递减的顺序排号之后就是
*1 2 1
*1 3 2
*2 3 4
*通过查找根节点我们首先是对1 2进行根节点查找即
*find(1) , find(2)可知find(1)==1,find(2)==2 不相等
*所以合并两点的根节点即find(2)==1;同理find(3)==1
*因为2,3都已经合并所以第三组数据2 3 4的价格4就不会
* 加到最小树的结果中去
*/
for(i=0;i<road;i++)
{
if(find(s[i].beg)!=find(s[i].end)) //当两点没有连接时才可以连接两点
{
mix(s[i].beg,s[i].end); //因为已经按照价钱从高到低排序好了所以可以找到
sum+=s[i].money; //在两个点 未相连的情况下的最小权值并将其相连
}
}
最小生成树之算法记录【prime算法+Kruskal算法】【模板】的更多相关文章
- 图论——最小生成树:Prim算法及优化、Kruskal算法,及时间复杂度比较
最小生成树: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边.简单来说就是有且仅有n个点n-1条边的连通图. 而最小生成树就是最小权 ...
- 关于最小生成树(并查集)prime和kruskal
适合对并查集有一定理解的人. 新手可能看不懂吧.... 并查集简单点说就是将相关的2个数字联系起来 比如 房子 1 2 3 4 5 6 ...
- 最小生成树之Prim算法,Kruskal算法
Prim算法 1 .概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gr ...
- [数据结构]最小生成树算法Prim和Kruskal算法
最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树. 例如,对于如上图G4所示的连通网可以有多棵权值总 ...
- 最小生成树Prim算法和Kruskal算法(转)
(转自这位大佬的博客 http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html ) Prim算法 1.概览 普里姆算法(Pr ...
- 最小生成树的Prim算法以及Kruskal算法的证明
Prime算法的思路:从任何一个顶点开始,将这个顶点作为最小生成树的子树,通过逐步为该子树添加边直到所有的顶点都在树中为止.其中添加边的策略是每次选择外界到该子树的最短的边添加到树中(前提是无回路). ...
- 最小生成树---Prim算法和Kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...
- 转载:最小生成树-Prim算法和Kruskal算法
本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...
- 数据结构与算法--最小生成树之Kruskal算法
数据结构与算法--最小生成树之Kruskal算法 上一节介绍了Prim算法,接着来看Kruskal算法. 我们知道Prim算法是从某个顶点开始,从现有树周围的所有邻边中选出权值最小的那条加入到MST中 ...
- 数据结构与算法系列----最小生成树(Prim算法&Kruskal算法)
一:Prim算法 1.概览 普里姆算法(Prim算法).图论中的一种算法.可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中.不但包含了连通图里的全部顶点(英语:Ve ...
随机推荐
- html标签data大写获取不到值:只能小写+横杠命名
html标签data大写获取不到值:只能小写+横杠命名 例如: <i class="glyphicon glyphicon-question-sign" data-tip-t ...
- mongodb3.2系统性学习——5、游标 模糊查询 findAndModify函数
1首先介绍查询结果 返回的过程: 进行查询的时候mongodb 并不是一次哪个返回结果集合的所有文档,而是以多条文档的形式分批返回查询的结果,返回文档到内存中. 好处: 减少了客户端与服务器端的查询负 ...
- 查看文章 mysql:表注释和字段注释[转]
1 创建表的时候写注释 create table test1 ( field_name int comment '字段的注释' )comment='表的注释'; 2 修改表的注释 alter tabl ...
- How to get Directory size in IsolatedStorage of Windows Phone 8 App
There is no API to get the total size of a specific directory in the isolated storage. Therefore, th ...
- 强大DevExpress,Winform LookUpEdit 实现多列查询 gridview弹出下拉选择 z
关键代码请参考http://www.devexpress.com/Support/Center/p/K18333.aspx 最新DEMO 下载 The current GridLookUpEdit's ...
- C++版 Chip8游戏模拟器
很早就想写个FC模拟器,但真是一件艰难的事情.. 所以先写个Chip8模拟器,日后再继续研究FC模拟器. Chip8只有35条指令,属于RISC指令集,4k内存,2k显存,16个寄存器(其中15个通用 ...
- ASP.NET 共用类库
using System; using System.Collections.Generic; using System.Text; using System.Web; using System.We ...
- JSP页面的五种跳转方法
①RequestDispatcher.forward() 是在服务器端起作用,当使用forward()时,Servlet engine传递HTTP请求从当前的Servlet or JSP到另外一个Se ...
- 意犹未尽而来的第一篇Android 逆向
游戏:咕噜王国大冒险 平台:android 目标: 1. 去除乱七八糟提示(本篇目标) 2. 去除google弹窗 3. 破解“all stages” 破文开始: 1. 使用APKIDE反编译:搜索字 ...
- EasyUI 调用getSelections方法只能获取到一行的原因
$('#tt').datagrid({ url: 'GetDataJosn', title: 'DataGrid', width: 800, height: 300, pageSize: 10, id ...