最小生成树(prime+kruskal)
1.prime算法
prime算法类似于bfs,就是判断每次连接的点中距离最短的,加入到树中,具体如下:
prime算法要求一开始随便选择一个点作为起点,因为最小生成树包括所有点,所以起点随机即可(一般选1),将该点加入一个集合,然后判断集合中所有点与之相连的点中最小的,将其加入集合中,加入集合的点都要用一个vis数组判断是否重复出现过,如果重复出现,就说明你要连接的这两个点已经是连通的了,不需要再直接连接。
比如: 图中三条边,分别为1,2,3,从1开始,1的连接的边两条<1,3>,<1,2>,很明显后者小,所以将后者放入集合,直接在以2为起点时候,判断2是否走过,没走过就说明可以加入树中,然后加入的是<1,3>判断3是否走过,没有加入树,然后就是<2,3>,这里不用纠结<2,3>还是<3,2>,无向图,存边存了两遍,正反各一遍,然后发现3走过,不能加入树,结束,最小生成树的大小是3。
2.kruskal算法
kruskal算法是并查集和贪心的应用,开始时将所有路径的起点,终点,权值加入到一个集合中,然后将集合排序,从小到大以此选择边加入树,为了保证最优,每次要判断加入的边的两端端点是否是相连的( 就是判断两个端点的最顶层父节点是否相同 ),如果不同,则加入树中。
模板
priority_queue<pll,vector<pll>,greater<pll> > q;
ll prime(){//prime算法,用链式前向星储存,堆优化
ll ans=0;
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
memset(vis,0,sizeof(vis));
q.push(make_pair(0,1));
while(!q.empty()&&sum<n){
int u=q.top().first;
int v=q.top().second;
q.pop();
if(vis[v]) continue;
sum++;
ans+=u;
vis[v]=1;
for(int i=head[v];i;i=e[i].next)
if(e[i].w<dis[e[i].to]) dis[e[i].to]=e[i].w,q.push(make_pair(dis[e[i].to],e[i].to));
}
return ans;
ll kru(){//kruskal模板
int ans=0;
sort(a+1,a+1+n*(n-1)/2,cmp);
for(int i=1;i<=n*(n-1)/2;i++){
ll px=find(a[i].x);ll py=find(a[i].y);
if(px!=py){
pre[px]=py;
if(a[i].w>0) ans+=a[i].w;
sum++;
}
if(sum==m-1) return ans;
}
return ans;
}
例题:畅通工程(模板题)
链接:Problem - 1863 (hdu.edu.cn)
题意:找出最小生成树,如过不能构成,就输出'?'。
代码: //kruskal写法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
struct ss{
ll x,y,w;
}a[N];
ll pre[N]; ll n,m;
ll find(ll x){
if(pre[x]==x) return x;
return pre[x]=find(pre[x]);
}
bool cmp(ss a,ss b){
return a.w<b.w;
}
ll cnt;
ll kru(){
int ans=0;
for(int i=1;i<=m;i++) pre[i]=i;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
ll px=find(a[i].x);ll py=find(a[i].y);
if(px!=py){
pre[px]=py;
if(a[i].w>0) ans+=a[i].w;
cnt++;
}
if(cnt==m-1) return ans;
}
return -1;
}
signed main(){
while(cin>>n>>m&&n){
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y>>a[i].w;
}
cnt=0;
ll t=kru();
if(t==-1) cout<<"?"<<endl;
else cout<<t<<endl;
}
}
prime 写法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=1e5+5;
struct ss{
ll to,w,next;
}e[N];
ll pre[N]; ll n,m;
ll cnt;ll head[N];
ll dis[N],vis[N];
void add(ll x,ll y,ll w){
e[++cnt].to=y;
e[cnt].w=w;
e[cnt].next=head[x];
head[x]=cnt;
}
priority_queue<pll,vector<pll>,greater<pll> > q;
ll sum;
ll prime(){
ll ans=0;
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
memset(vis,0,sizeof(vis));
q.push(make_pair(0,1));
while(!q.empty()&&sum<n){
int u=q.top().first;
int v=q.top().second;
q.pop();
if(vis[v]) continue;
sum++;
ans+=u;
vis[v]=1;
for(int i=head[v];i;i=e[i].next)
if(e[i].w<dis[e[i].to]) dis[e[i].to]=e[i].w,q.push(make_pair(dis[e[i].to],e[i].to));
}
return ans;
}
signed main(){
while(cin>>n>>m&&n){
cnt=0;
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++){
ll x,y,w;cin>>x>>y>>w;
add(x,y,w);add(y,x,w);
}
sum=0;
ll t=prime();
if(sum==m) cout<<t<<endl;
else cout<<"?"<<endl;
}
}
例题:继续畅通工程
链接:Problem - 1879 (hdu.edu.cn)
题意:开始已经建造了一些路径,找最小生成树
思路:kruskal就是输入的时候将已经存在的边直接放到并查集中,链接他们的父节点,让他们相通。
prime就是输入的时候将存在的边的权值按0输入即可。
代码:prime算法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=1e5+5;
struct ss{
ll to,w,next;
}e[N];
ll pre[N]; ll n,m;
ll cnt;ll head[N];
ll dis[N],vis[N];
void add(ll x,ll y,ll w){
e[++cnt].to=y;
e[cnt].w=w;
e[cnt].next=head[x];
head[x]=cnt;
}
priority_queue<pll,vector<pll>,greater<pll> > q;
ll sum;
ll prime(){
ll ans=0;
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
memset(vis,0,sizeof(vis));
q.push(make_pair(0,1));
while(!q.empty()&&sum<n){
int u=q.top().first;
int v=q.top().second;
q.pop();
if(vis[v]) continue;
sum++;
ans+=u;
vis[v]=1;
for(int i=head[v];i;i=e[i].next)
if(e[i].w<dis[e[i].to]) dis[e[i].to]=e[i].w,q.push(make_pair(dis[e[i].to],e[i].to));
}
return ans;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>n&&n){
cnt=0;
memset(head,0,sizeof(head));
for(int i=1;i<=n*(n-1)/2;i++){
ll x,y,w,p;cin>>x>>y>>w>>p;
if(p==1) {
add(x,y,0),add(y,x,0);
}
else add(x,y,w),add(y,x,w);
}
sum=0;
cout<<prime()<<endl;
}
}
kruskal算法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
struct ss{
ll x,y,w;
}a[N];
ll pre[N]; ll n,m;
ll find(ll x){
if(pre[x]==x) return x;
return pre[x]=find(pre[x]);
}
bool cmp(ss a,ss b){
return a.w<b.w;
}
ll cnt,sum;
ll kru(){
int ans=0;
sort(a+1,a+1+n*(n-1)/2,cmp);
for(int i=1;i<=n*(n-1)/2;i++){
ll px=find(a[i].x);ll py=find(a[i].y);
if(px!=py){
pre[px]=py;
if(a[i].w>0) ans+=a[i].w;
sum++;
}
if(sum==m-1) return ans;
}
return ans;
}
signed main(){
while(cin>>n&&n){
for(int i=1;i<=n;i++) pre[i]=i;
cnt=0;
for(int i=1;i<=n*(n-1)/2;i++){
ll x,y,w,p;cin>>x>>y>>w>>p;
if(p==1){
ll px=find(x);ll py=find(y);
pre[px]=py;
}
else a[++cnt].x=x,a[cnt].y=y,a[cnt].w=w;
}
sum=0;
cout<<kru()<<endl;
}
}
最小生成树(prime+kruskal)的更多相关文章
- 最小生成树 prime poj1258
题意:给你一个矩阵M[i][j]表示i到j的距离 求最小生成树 思路:裸最小生成树 prime就可以了 最小生成树专题 AC代码: #include "iostream" #inc ...
- 最小生成树 prime + 队列优化
存图方式 最小生成树prime+队列优化 优化后时间复杂度是O(m*lgm) m为边数 优化后简直神速,应该说对于绝大多数的题目来说都够用了 具体有多快呢 请参照这篇博客:堆排序 Heapsort / ...
- 最小生成树的Kruskal算法实现
最近在复习数据结构,所以想起了之前做的一个最小生成树算法.用Kruskal算法实现的,结合堆排序可以复习回顾数据结构.现在写出来与大家分享. 最小生成树算法思想:书上说的是在一给定的无向图G = (V ...
- 最小生成树之Kruskal
模板题,学习一下最小生成树的Kruskal算法 对于一个连通网(连通带权图,假定每条边上的权均为大于零的实数)来说,每棵树的权(即树中所有边的权值总和)也可能不同 具有权最小的生成树称为最小生成树 生 ...
- ZOJ 1203 Swordfish 旗鱼 最小生成树,Kruskal算法
主题链接:problemId=203" target="_blank">ZOJ 1203 Swordfish 旗鱼 Swordfish Time Limit: 2 ...
- 经典问题----最小生成树(kruskal克鲁斯卡尔贪心算法)
题目简述:假如有一个无向连通图,有n个顶点,有许多(带有权值即长度)边,让你用在其中选n-1条边把这n个顶点连起来,不漏掉任何一个点,然后这n-1条边的权值总和最小,就是最小生成树了,注意,不可绕成圈 ...
- 最小生成树 Prim Kruskal
layout: post title: 最小生成树 Prim Kruskal date: 2017-04-29 tag: 数据结构和算法 --- 目录 TOC {:toc} 最小生成树Minimum ...
- 数据结构与算法--最小生成树之Kruskal算法
数据结构与算法--最小生成树之Kruskal算法 上一节介绍了Prim算法,接着来看Kruskal算法. 我们知道Prim算法是从某个顶点开始,从现有树周围的所有邻边中选出权值最小的那条加入到MST中 ...
- hdu 1875 最小生成树 prime版
最小生成树prime版 大致的步骤 首先选取一个到集合最近的点 然后标记起在集合内部 然后更新最短距离 畅通工程再续 Time Limit: 2000/1000 MS (Java/Others) ...
随机推荐
- php类精确验证身份证号码
<?php // check class check{ // $num为身份证号码,$checkSex:1为男,2为女,不输入为不验证 public function checkIdentity ...
- Javaweb-IDEA 中Maven的操作
1. 在idea中使用Maven 启动idea 创建一个MavenWeb项目 3.等待项目初始化完毕 4. 观察maven仓库中多了哪些东西 5. idea中的maven设置 注意:idea项目创成功 ...
- 『忘了再学』Shell流程控制 — 39、特殊流程控制语句
目录 1.特殊流程控制语句介绍 2.exit语句 3.break语句 4.continue语句 1.特殊流程控制语句介绍 Shell程序或者说其他的程序,都是顺序执行的,也就是第一行执行完再执行第二行 ...
- Vue是怎么渲染template内的标签内容的?
我们在使用Vue做项目时,都会用到脚手架,相应的我们会在template写标签内容.那么你知道为什么会在template写标签吗?这当中经过了怎样的处理呢? <template> < ...
- 执行docker一系列命令失败
出现这种情况之后,执行下面的命令即可. systemctl restart docker
- 【最全】CSS盒子(div)水平垂直居中居然还有这种方式
最全的CSS盒子(div)水平垂直居中布局,对CSS 布局掌握程度决定你在 Web 开发中的开发页面速度. 相对于屏幕 方法一:利用定位 <div class="box"&g ...
- 从Python到水一篇AI论文(核心 or Sci三区+)
博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...
- C++学习记录1
代码1:转义字符 点击查看代码 #include<iostream> using namespace std; void test01()//换行 { cout << &quo ...
- Docker安装及基础命令
一.docker安装 1.安装docker #关闭防火墙和selinux systemctl stop firewalld.service setenforce 0 #安装依赖包 yum ins ...
- 渲染优化中那些奇奇怪怪的rules
禁⽌使⽤ iframe iframe 会阻塞主⻚⾯的 Onload 事件 搜索引擎的检索程序⽆法解读这种⻚⾯,不利于 SEO iframe 和主⻚⾯共享连接池,⽽浏览器对相同域的连接有限制,所以会影响 ...