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)的更多相关文章

  1. 最小生成树 prime poj1258

    题意:给你一个矩阵M[i][j]表示i到j的距离 求最小生成树 思路:裸最小生成树 prime就可以了 最小生成树专题 AC代码: #include "iostream" #inc ...

  2. 最小生成树 prime + 队列优化

    存图方式 最小生成树prime+队列优化 优化后时间复杂度是O(m*lgm) m为边数 优化后简直神速,应该说对于绝大多数的题目来说都够用了 具体有多快呢 请参照这篇博客:堆排序 Heapsort / ...

  3. 最小生成树的Kruskal算法实现

    最近在复习数据结构,所以想起了之前做的一个最小生成树算法.用Kruskal算法实现的,结合堆排序可以复习回顾数据结构.现在写出来与大家分享. 最小生成树算法思想:书上说的是在一给定的无向图G = (V ...

  4. 最小生成树之Kruskal

    模板题,学习一下最小生成树的Kruskal算法 对于一个连通网(连通带权图,假定每条边上的权均为大于零的实数)来说,每棵树的权(即树中所有边的权值总和)也可能不同 具有权最小的生成树称为最小生成树 生 ...

  5. ZOJ 1203 Swordfish 旗鱼 最小生成树,Kruskal算法

    主题链接:problemId=203" target="_blank">ZOJ 1203 Swordfish 旗鱼 Swordfish Time Limit: 2 ...

  6. 经典问题----最小生成树(kruskal克鲁斯卡尔贪心算法)

    题目简述:假如有一个无向连通图,有n个顶点,有许多(带有权值即长度)边,让你用在其中选n-1条边把这n个顶点连起来,不漏掉任何一个点,然后这n-1条边的权值总和最小,就是最小生成树了,注意,不可绕成圈 ...

  7. 最小生成树 Prim Kruskal

    layout: post title: 最小生成树 Prim Kruskal date: 2017-04-29 tag: 数据结构和算法 --- 目录 TOC {:toc} 最小生成树Minimum ...

  8. 数据结构与算法--最小生成树之Kruskal算法

    数据结构与算法--最小生成树之Kruskal算法 上一节介绍了Prim算法,接着来看Kruskal算法. 我们知道Prim算法是从某个顶点开始,从现有树周围的所有邻边中选出权值最小的那条加入到MST中 ...

  9. hdu 1875 最小生成树 prime版

    最小生成树prime版 大致的步骤 首先选取一个到集合最近的点 然后标记起在集合内部 然后更新最短距离 畅通工程再续 Time Limit: 2000/1000 MS (Java/Others)    ...

随机推荐

  1. 认识弹性盒子flex

    认识弹性盒子flex 来源:https://blog.xybin.top/2022/flex 1.定义弹性布局(父级上定义)display:flex; 如果说内核为webkit 的必须前面加上 -we ...

  2. 记住这几个git命令就够了

    git clone: 下载初始化git add:添加git commit -m ' ' :提交 带消息git push:推送git pull: 拉取 git config --global user. ...

  3. VueX的模块你知道多少?

    为什么会出现VueX的模块呢?当你的项目中代码变多的时候,很难区分维护.那么这时候Vuex的模块功能就这么体现出来了. 那么我们就开始吧!一.模块是啥? /* eslint-disable no-un ...

  4. 基于Vue.js的Web视频播放器插件vue-vam-video@1.3.6 正式发布

    前言 今日正式发布一款基于Vue.js的Web视频播放器插件.可配置,操作灵活.跟我一起来体验吧! 线上地址体验 基于vue3.0和vue-vam-video,我开发了一款在线视频播放器. 网址: h ...

  5. Vue2自定义插件的写法-Vue.use()

    最近在用vue2完善一个项目,顺便温习下vue2的基础知识点! 有些知识点恰好没用到时间一长就会淡忘,这样对自己是一种损失. 定义一个对象 对象里可以有任何内容 但install的函数是必不可少的,因 ...

  6. 使用C++的ORM框架QxORM

    QxORM中,我们用的最多的无非是这两点 官方表述是这样的: 持久性: 支持最常见的数据库,如 SQLite.MySQL.PostgreSQL.Oracle.MS SQL Server.MongoDB ...

  7. Qt项目开发实例 (含源码)

    源码传送门: 啊渊 / QT博客案例 · GitCode 目前QT的研发都是基于windows操作系统的,本文分享在国产操作系统中学QT的路线图,其实学习路线差不多,为了全面的回顾自己的学习知识,打算 ...

  8. oracle备份数据库数据及导入数据库

    1.oracle数据库备份和导入 bat 脚本 scott oracle数据库用户名称 123456 数据库scott用户下的密码 192.168.124.8 本电脑IP orcl 为oracle库 ...

  9. CSS基本知识点——带你走进CSS的新世界

    CSS基本知识点 我们在学习HTML之后,前端三件套第二件便是CSS,但CSS内容较多,我们分几部分讲解: (如果没有学习HTML,请参考之前文章:HTML知识点概括--一篇文章带你完全掌握HTML& ...

  10. Unique -「企划」新生守则(?

    随想随记,主要是整活. 红色贝雷帽大爷会在校园不定期游走,遇见记得打招呼. 面食堂冰沙类饮品请快速解决或者边喝边搅,如果发现饮品甜度骤减请快速前往最近的垃圾桶扔掉. 关于散养猫小黄和小黑. 如果看见小 ...