模板<最小生成树>
最小生成树浅谈
这里介绍最小生成树的两种方法:Prim和Kruskal。
两者区别:Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣。Prim是以更新过的节点的连边找最小值,Kruskal是直接将边排序。
两者其实都是运用贪心的思路
洛谷数据:
Prim:
个人觉得Prim和最短路中的dijkstra很像,由于速度问题,所以这里我用链式前向星存图。Prim的思想是将任意节点作为根,再找出与之相邻的所有边(用一遍循环即可),再将新节点更新并以此节点作为根继续搜,维护一个数组:dis,作用为已用点到未用点的最短距离。
证明:Prim算法之所以是正确的,主要基于一个判断:对于任意一个顶点v,连接到该顶点的所有边中的一条最短边(v, vj)必然属于最小生成树(即任意一个属于最小生成树的连通子图,从外部连接到该连通子图的所有边中的一条最短边必然属于最小生成树)
具体算法流程图解如下:
注意:inline和register为一点点常数优化,不要的话也可以过,不理解的同学删掉即可
- #include<bits/stdc++.h>
- using namespace std;
- #define re register
- #define il inline
- il int read()
- {
- re ,f=;char c=getchar();
- ;c=getchar();}
- )+(x<<)+(c^),c=getchar();
- return x*f;
- }//快读,不理解的同学用cin代替即可
- #define inf 123456789
- #define maxn 5005
- #define maxm 200005
- struct edge
- {
- int v,w,next;
- }e[maxm<<];
- //注意是无向图,开两倍数组
- ,ans;
- //已经加入最小生成树的的点到没有加入的点的最短距离,比如说1和2号节点已经加入了最小生成树,那么dis[3]就等于min(1->3,2->3)
- bool vis[maxn];
- //链式前向星加边
- il void add(int u,int v,int w)
- {
- e[++cnt].v=v;
- e[cnt].w=w;
- e[cnt].next=head[u];
- head[u]=cnt;
- }
- //读入数据
- il void init()
- {
- n=read(),m=read();
- ,u,v,w;i<=m;++i)
- {
- u=read(),v=read(),w=read();
- add(u,v,w),add(v,u,w);
- }
- }
- il int prim()
- {
- //先把dis数组附为极大值
- ;i<=n;++i)
- {
- dis[i]=inf;
- }
- //这里要注意重边,所以要用到min
- ];i;i=e[i].next)
- {
- dis[e[i].v]=min(dis[e[i].v],e[i].w);
- }
- while(++tot<n)//最小生成树边数等于点数-1
- {
- re int minn=inf;//把minn置为极大值
- vis[now]=;//标记点已经走过
- //枚举每一个没有使用的点
- //找出最小值作为新边
- //注意这里不是枚举now点的所有连边,而是1~n
- ;i<=n;++i)
- {
- if(!vis[i]&&minn>dis[i])
- {
- minn=dis[i];
- now=i;
- }
- }
- ans+=minn;
- //枚举now的所有连边,更新dis数组
- for(re int i=head[now];i;i=e[i].next)
- {
- re int v=e[i].v;
- if(dis[v]>e[i].w&&!vis[v])
- {
- dis[v]=e[i].w;
- }
- }
- }
- return ans;
- }
- int main()
- {
- init();
- printf("%d",prim());
- ;
- }
Prim
Kruskal:
Kruskal算法的思想比Prin好理解一些。先把边按照权值进行排序,用贪心的思想优先选取权值较小的边,并依次连接,若出现环则跳过此边(用并查集来判断是否存在环)继续搜,直到已经使用的边的数量比总点数少一即可。
证明:刚刚有提到:如果某个连通图属于最小生成树,那么所有从外部连接到该连通图的边中的一条最短的边必然属于最小生成树。所以不难发现,当最小生成树被拆分成彼此独立的若干个连通分量的时候,所有能够连接任意两个连通分量的边中的一条最短边必然属于最小生成树
具体算法流程图解如下:
并查集详解
- #include<bits/stdc++.h>
- using namespace std;
- #define re register
- #define il inline
- il int read()
- {
- re ,f=;char c=getchar();
- ;c=getchar();}
- )+(x<<)+(c^),c=getchar();
- return x*f;
- }
- struct Edge
- {
- int u,v,w;
- }edge[];
- ],n,m,ans,eu,ev,cnt;
- il bool cmp(Edge a,Edge b)
- {
- return a.w<b.w;
- }
- //快排的依据(按边权排序)
- il int find(int x)
- {
- while(x!=fa[x]) x=fa[x]=fa[fa[x]];
- return x;
- }
- //并查集循环实现模板,及路径压缩,不懂并查集的同学可以戳一戳代码上方的“并查集详解”
- il void kruskal()
- {
- sort(edge,edge+m,cmp);
- //将边的权值排序
- ;i<m;i++)
- {
- eu=find(edge[i].u), ev=find(edge[i].v);
- if(eu==ev)
- {
- continue;
- }
- //若出现两个点已经联通了,则说明这一条边不需要了
- ans+=edge[i].w;
- //将此边权计入答案
- fa[ev]=eu;
- //将eu、ev合并
- )
- {
- break;
- }
- //循环结束条件,及边数为点数减一时
- }
- }
- int main()
- {
- n=read(),m=read();
- ;i<=n;i++)
- {
- fa[i]=i;
- }
- //初始化并查集
- ;i<m;i++)
- {
- edge[i].u=read(),edge[i].v=read(),edge[i].w=read();
- }
- kruskal();
- printf("%d",ans);
- ;
- }
Kruskal
PS:由于个人码风习惯,代码可能看上去较长,但其实自己写起来还是比较短的。
模板<最小生成树>的更多相关文章
- 前端模板<script type="text/template" id="tmpl">
前端模板, 比连接字符串好用多了, 还可以使用循环\判断等语句, 减少工作量 <script type="text/template" id="member-tmp ...
- <script type="text/x-template"> 模板
获取动态的js模板可以用art-template插件 <script type="text/template"> 给<script>设置type=" ...
- 关于 <script type='text/template' > 的妙用 / 使用jquery获取iframe加载完成事件
https://www.cnblogs.com/ddqyc/p/6200539.html <!DOCTYPE html> <html> <head> <met ...
- Js script type="text/template"的使用简单说明
<script type="text/template" id="treeTableTpl"> <tr id="{{row.id}} ...
- script标签中type为<script type="text/x-template">是个啥
写过一点前端的都会碰到需要使用JS字符串拼接HTML元素然后append到页面DOM树上的情况,一般的写法都是使用+号以字符串的形式拼接,如果是短点的还好,如果很长很长的话就会拼接到令人崩溃了. 比如 ...
- document.write('<script type=\"text/javascript\"><\/script>')
document.write('<script type=\"text/javascript\"><\/script>')
- <script type="text/html"></script> js模版使用
<div></div> <script type="text/html" id="javascript_template"> ...
- <script language = "javascript">, <script type = "text/javascript">和<script language = "application/javascript">(转)
application/javascript是服务器端处理js文件的mime类型,text/javascript是浏览器处理js的mime类型,后者兼容性更好(虽然application/ ...
- 哪种写法更好?<script></script> vs/or <script type=”text/javasript”></script>
一直很奇怪 哪种写法更好<script type=“text/javascript”>…</script> or <script>…</script>? ...
- <script type="text/template">是干什么的,为什么要把html写在js中? 这是什么编程语言风格,都能这样用吗?
这一段存放了一个模板.在js里面,经常需要使用js往页面中插入html内容.比如这样: var number = 123; $('#d').append('<div class="t& ...
随机推荐
- Sql 2000系统表 语句查询表结构
SQL2000系统表的应用 –1:获取当前数据库中的所有用户表 select Name from sysobjects where xtype=’u’ and status>=0 –2:获取 ...
- how browser handler file:/// link
1. why browser can only open .txt file directly, pop up open or save dialog for others? 2. html cann ...
- php 分析2
a:link,a:visited,a:hover,a:active 1:解释 link:连接平常的状态 visited:连接被访问过之后 hover:鼠标放到连接上的时候 active:连接被按下 ...
- vue http请求 vue-resource使用方法
1.安装vue-resource扩展: npm install vue-resource 2.在main.js中引入 import http from 'vue-resource' 3.使用方法 // ...
- Nginx upstream负载均衡配置
1.在http节点下添加 upstream test { server 127.0.0.1:16010; server 127.0.0.1:16011; } 2.把server 节点下 ...
- vs 2017注册码 激活码
Visual Studio 2017(VS2017) 企业版 Enterprise 注册码:NJVYC-BMHX2-G77MM-4XJMR-6Q8QFVisual Studio 2017(VS2017 ...
- kafka客户端发布record(消息)
kafka客户端发布record(消息)到kafka集群. 新的生产者是线程安全的,在线程之间共享单个生产者实例,通常单例比多个实例要快. 一个简单的例子,使用producer发送一个有序的key/v ...
- [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题目中这种多个串匹配的问题,一下子就想到了AC自动机.然后发现如果要建立AC自动机, ...
- 19/03/04 vue基础整理,webpack基础整理
gitUrl : https://gitee.com/jinyujiang/vue_basis_example.git (迭代更新) webpack : 有道云笔记分享 以及码云(迭代更新)
- Handler消息机制的一些原理(直接用code讲解)——Android开发
package com.example.handlertest; import android.os.Bundle; import android.os.Handler; import android ...