关于图的几个概念定义:

        

关于图的几个概念定义:

  • 连通图:在无向图中,若任意两个顶点vi与vj都有路径相通,则称该无向图为连通图。
  • 强连通图:在有向图中,若任意两个顶点vi与vj都有路径相通,则称该有向图为强连通图。
  • 连通网:在连通图中,若图的边具有一定的意义,每一条边都对应着一个数,称为权;权代表着连接连个顶点的代价,称这种连通图叫做连通网。
  • 生成树一个连通图的生成树是指一个连通子图,它含有图中全部n个顶点,但只有足以构成一棵树的n-1条边。一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。
  • 最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。

构造最小生成树的准则有3条:

(1)必须只使用该网络中的边来构造最小生成树。

(2)必须使用且仅使用n-1条边来连接网络中的n个顶点。

(3)不能使用产生回路的边。



下面介绍两种求最小生成树算法

1 Prim(普利姆算法)算法--加点法

此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

Prim算法从任意一个顶点开始,每次选择一个与当前顶点集最近的一个顶点,并将两顶点之间的边加入到树中。Prim算法在找当前最近顶点时使用到了贪婪算法。

实现过程:

图例 说明 不可选 可选 已选(Vnew

此为原始的加权连通图。每条边一侧的数字代表其权值。 - - -

顶点D被任意选为起始点。顶点ABEF通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。 C, G A, B, E, F D

下一个顶点为距离DA最近的顶点。BD为9,距A为7,E为15,F为6。因此,FDA最近,因此将顶点F与相应边DF以高亮表示。 C, G B, E, F A, D
算法继续重复上面的步骤。距离A为7的顶点B被高亮表示。 C B, E, G A, D, F

在当前情况下,可以在CEG间进行选择。CB为8,EB为7,GF为11。E最近,因此将顶点E与相应边BE高亮表示。 C, E, G A, D, F, B

这里,可供选择的顶点只有CGCE为5,GE为9,故选取C,并与边EC一同高亮表示。 C, G A, D, F, B, E

顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EG G A, D, F, B, E, C

现在,所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。 A, D, F, B, E, C, G
 #include<stdio.h>
#include<string.h>
#define MAX 0x3f3f3f3f
using namespace std;
int logo[];///用0和1来表示是否被选择过
int map1[][];
int dis[];///记录任意一点到这一点的最近的距离
int n,m;
int prim()
{
int i,j,now;
int sum=;
for(i=;i<=n;i++)///初始化
{
dis[i]=MAX;
logo[i]=;
}
for(i=;i<=n;i++)
{
dis[i]=map1[][i];
}
dis[]=;
logo[]=;
for(i=;i<n;i++)///循环查找
{
now=MAX;
int min1=MAX;
for(j=;j<=n;j++)
{
if(logo[j]==&&dis[j]<min1)
{
now=j;
min1=dis[j];
}
}
if(now==MAX)///防止不成图
{
break;
}
logo[now]=;
sum=sum+min1;
for(j=;j<=n;j++)///填入新点后更新最小距离,到顶点集的距离
{
if(logo[j]==&&dis[j]>map1[now][j])
{
dis[j]=map1[now][j];
}
}
}
if(i<n)
{
printf("?\n");
}
else
{
printf("%d\n",sum);
}
}
int main()
{
while(scanf("%d%d",&m,&n)!=EOF)///n是点数
{
if(m==)
{
break;
}
memset(map1,0x3f3f3f3f,sizeof(map1));///map是邻接矩阵储存图的信息
for(int i=;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(c<map1[a][b])///防止出现重边
{
map1[a][b]=map1[b][a]=c;
}
}
prim();
}
return ;
}

邻接表实现:

 #include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
int end;///终点
int power;///权值
} t;
int n;///n为点数
vector<node>q[];///邻接表储存图的信息
int dis[];///距离
int vis[];///标记数组
void prime()
{
int i,len,j,pos,sum,start;
memset(vis,,sizeof(vis));
sum=;
start=;///任意取起点
for(i=; i<=n; i++)
{
dis[i]=INF;
}
len=q[start].size();
for(i=; i<len; i++)///从任意起点开始的dis数组更新
{
if(q[start][i].power<dis[q[start][i].end])
{
dis[q[start][i].end]=q[start][i].power;
}
}
vis[start]=;
for(j=; j<n-; j++)
{
int pos,min=INF;
for(i=; i<=n; i++)
{
if(vis[i]!=&&dis[i]<min)
{
min=dis[i];
pos=i;///找到未访问节点中权值最小的
}
}
if(pos==INF)///防止不成图
{
break;
}
vis[pos]=;
sum=sum+min;
len=q[pos].size();///再次更新dis数组
for(j=; j<len; j++)
{
if(vis[q[pos][j].end]==&&dis[q[pos][j].end]>q[pos][j].power)
{
dis[q[pos][j].end] = q[pos][j].power;
}
}
}
if(j<n)
{
printf("?\n");
}
else
{
printf("%d\n",sum);
}
}
int main()
{
int m,i;
int begin,end,power;
int a,b;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=; i<=n; i++)
{
q[i].clear();///将victor数组清空
}
for(i=; i<m; i++)
{
scanf("%d%d%d",&begin,&end,&power);///输入
t.end=end;
t.power=power;
q[begin].push_back(t);
t.end=begin;///无向图
t.power=power;
q[end].push_back(t);
}
prime();
}
return ;
}

这里再给出一个没有使用标记数组的代码:

int prim(int s)
{
int i,j,sum=;
int now;
for(i=;i<=n;i++)
{
closest[i]=INT_MAX;
}
for(i=;i<=n;i++)
{
closest[i]=map[s][i];
}
closest[s]=;
for(i=;i<n;i++)//这里的i代表的是边数,有n个点就会有n-1条边
{
int min=INT_MAX;
for(j=;j<=n;j++)
{
if(closest[j]&&closest[j]<min)
{
min=closest[j];
now=j;//找到所需的最小边
}
}
sum+=min;
closest[now]=;//将找到的边加入到最小生成树之中
for(j=;j<=n;j++)//找到新的点加入已选点集合之后,更新该点到未选点集合的距离
{
if(map[now][j]&&map[now][j]<closest[j])
{
closest[j]=map[now][j];
}
}
}
return sum;
}

Kruskal(克鲁斯卡尔)算法--加边法

1.概览

  Kruskal算法是一种用来寻找最小生成树的算法,在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边。

2.实现过程

1).记Graph中有v个顶点,e个边

2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边

3).将原图Graph中所有e个边按权值从小到大排序

4).循环:从权值最小的边开始遍历每条边 直至图Graph中所有的节点都在同一个连通分量中  if 这条边连接的两个节点于图Graphnew中不在同一个连通分量中   添加这条边到图Graphnew

  图例描述:

首先第一步,我们有一张图Graph,有若干点和边

将所有的边的长度排序,用排序的结果作为我们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资源进行选择,排序完成后,我们率先选择了边AD。这样我们的图就变成了下图

在剩下的变中寻找。我们找到了CE。这里边的权重也是5

依次类推我们找到了6,7,7,即DF,AB,BE。

下面继续选择, BC或者EF尽管现在长度为8的边是最小的未选择的边。但是现在他们已经连通了(对于BC可以通过CE,EB来连接,类似的EF可以通过EB,BA,AD,DF来接连)。所以不需要选择他们。类似的BD也已经连通了(这里上图的连通线用红色表示了)。最后就剩下EG和FG了。当然我们选择了EG。

代码:(利用并查集来实现)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,sum;
struct node
{
int start;///起点
int end;///终点
int power;///权值
}edge[];
int pre[];
int cmp(node a,node b)
{
return a.power<b.power;///按权值排序
}
int Find(int x)///并查集找祖先
{
if(x!=pre[x])///递归法
{
pre[x]=Find(pre[x]);
}
return pre[x]; /*int a;///循环法
a=x;
while(pre[a]!=a)
{
a=pre[a];
}
return a;*/
}
void Union(int x,int y,int n)
{
int fx =Find(x);
int fy =Find(y);
if(fx!=fy)
{
pre[fx]=fy;
sum+=edge[n].power;
}
}
int main()
{
int i;
while(scanf("%d",&n)!=EOF)
{
sum=;
m=n*(n-)/;
for(i=;i<=m;i++)
{
scanf("%d%d%d",&edge[i].start,&edge[i].end,&edge[i].power);
}
for(i=;i<=m;i++)///并查集的初始化
{
pre[i]=i;
}
sort(edge+,edge+m+,cmp);
for(i=;i<=m;i++)
{
Union(edge[i].start,edge[i].end,i);
}
printf("%d\n",sum);
}
return ;
}

最小生成树(Kruskal和Prim算法)的更多相关文章

  1. 最小生成树——Kruskal与Prim算法

    最小生成树——Kruskal与Prim算法 序: 首先: 啥是最小生成树??? 咳咳... 如图: 在一个有n个点的无向连通图中,选取n-1条边使得这个图变成一棵树.这就叫“生成树”.(如下图) 每个 ...

  2. 关于最小生成树 Kruskal 和 Prim 的简述(图论)

    模版题为[poj 1287]Networking. 题意我就不说了,我就想简单讲一下Kruskal和Prim算法.卡Kruskal的题似乎几乎为0.(●-`o´-)ノ 假设有一个N个点的连通图,有M条 ...

  3. Kruskal和Prim算法求最小生成树

    Kruskal算法求最小生成树 测试数据: 5 6 0 1 5 0 2 3 1 2 4 2 4 2 2 3 1 1 4 1 输出: 2 3 1 1 4 1 2 4 2 0 2 3 思路:在保证不产生回 ...

  4. 最小生成树的kruskal、prim算法

    kruskal算法和prim算法 都说 kruskal是加边法,prim是加点法 这篇解释也不错:这篇 1.kruskal算法 因为是加边法,所以这个方法比较合适稀疏图.要码这个需要先懂并查集.因为我 ...

  5. 1.1.2最小生成树(Kruskal和Prim算法)

    部分内容摘自 勿在浮沙筑高台 http://blog.csdn.net/luoshixian099/article/details/51908175 关于图的几个概念定义: 连通图:在无向图中,若任意 ...

  6. 算法导论--最小生成树(Kruskal和Prim算法)

    转载出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51908175 关于图的几个概念定义: 连通图:在无向图中,若任意两个顶 ...

  7. 数据结构与算法--最小生成树之Prim算法

    数据结构与算法--最小生成树之Prim算法 加权图是一种为每条边关联一个权值或称为成本的图模型.所谓生成树,是某图的一棵含有全部n个顶点的无环连通子图,它有n - 1条边.最小生成树(MST)是加权图 ...

  8. [讲解]prim算法<最小生成树>

    最小生成树的方法一般比较常用的就是kruskal和prim算法 一个是按边从小到大加,一个是按点从小到大加,两个方法都是比较常用的,都不是很难... kruskal算法在本文里我就不讲了,本文的重点是 ...

  9. hiho 1097 最小生成树一·Prim算法 (最小生成树)

    题目: 时间限制:10000ms 单点时限:1000ms 内存限制:256MB   描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问 ...

随机推荐

  1. 搜索 水题&&错误集锦

    引子: 本以为搜索的题目老师也不会检查,结果今天早上loli慢悠悠的说:“请同学们提交一下搜索的题目~”,顿时心旌摇曳,却也只能装作镇定自若的样子,点了点头.. 然后就开始了今天的疯狂做题,虽说题目都 ...

  2. ABAP术语-Transaction

    Transaction 原文:http://www.cnblogs.com/qiangsheng/archive/2008/03/19/1112804.html Logical process in ...

  3. MySQL数据库安装配置步骤详解

    MYSQL的安装 1.打开下载的mysql安装文件mysql-5.5.27-win32.zip,双击解压缩,运行“setup.exe”. 2.选择安装类型,有“Typical(默认)”.“Comple ...

  4. Linux性能检查命令总结[转]

    一些常用的网络.IO.内存监控指令,Linux性能检查命令总结

  5. Jquery中复选框选中取消实现文本框的显示隐藏

    标签内容 <div class="box"> 请编写javascript代码,完成如下功能要求:<br /> 1.取消复选款后,要求促销价格.促销开始结束日 ...

  6. python3.X 安装web.py 失败的解决方法

    python2.x 安装python是非常顺利的 但是 在进行 pip3 install web.py 时提示很多错误 例如缺少模块 语法错误...... 最后试了一下web.py 的dev版本 pi ...

  7. hadoop生态搭建(3节点)-09.flume配置

    # http://archive.apache.org/dist/flume/1.8.0/# ===================================================== ...

  8. 树莓派驱动DHT22

    树莓派-DHT22测量湿度 一般的温湿度传感器有dht11和dht22,dht11比较便宜,dht22比dht11贵好几倍,自然测量的准确度肯定是dht22高一些.追求更高精准度的可以使用SHT1x. ...

  9. Springboot 拦截器(HandlerInterceptorAdapter)中注入无效

    1,传统filter和HandlerInterceptorAdapter的区别 springboot对传统Filter进行增强,添加更多细粒度的操作,分别实现预处理.后处理(调用了Service并返回 ...

  10. Solr第一讲——概述与入门

    一.solr介绍 1.什么是solr Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务器.Solr可以独立运行在Jetty.Tomcat等这些Serv ...