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. JAVA面向对象之封装和调用

    一   面向对象 面向对象的三大特性   1 封装:概念:封装是把过程和数据私有化,打包封存起来,对数据访问只能通过指定的方式.简单的可以理解为你把钱存到银行里,银行专员首先要给你开一个账户,之后你的 ...

  2. 机器学习中 TP FP TN FN的概念

    二分类 在二分类问题中,TP FP TN FN 是非常清楚且易于理解的. TP (True Positive) : 预测为 1 ,真实值也为 1 -> 真阳性 FP (False Positiv ...

  3. Redis 切片集群的数据倾斜分析

    Redis 中如何应对数据倾斜 什么是数据倾斜 数据量倾斜 bigkey导致倾斜 Slot分配不均衡导致倾斜 Hash Tag导致倾斜 数据访问倾斜 如何发现 Hot Key Hot Key 如何解决 ...

  4. 03 转换css元素的类别

    03 转换css元素的类别 通过设置display属性 属性 作用 block 块级 inline 行内 inline-block 行内块级 接来下 就跟着小demo来学习吧! 不懂可以看看!!!什么 ...

  5. Linux 文件权限相关知识

    文件权限说明 Linux中的文件能否被访问和工具(程序)无关,和访问的用户身份有关(谁去运行这个程序) 进程的发起者(谁去运行这个程序). 进程的发起者若是文件的所有者: 拥有文件的属主权限 进程的发 ...

  6. Tapdata 实时数据融合平台解决方案(五):落地

    作者介绍:TJ,唐建法,Tapdata 钛铂数据 CTO,MongoDB中文社区主席,原MongoDB大中华区首席架构师,极客时间MongoDB视频课程讲师. 通过前面几篇文章,我们从企业数据整合与分 ...

  7. 如何快速体验OneOS

    随便逛了逛 之前有简单了解过OneOS,今天逛了下OneOS专区,发现官方终于也在宣传方面发力了啊,很多文章都非常专业,也有开发者在专区里面提问题了.也发现,部分开发者倒在了第一步,如何编译下载运行O ...

  8. 快速入门python看过的一些资料

    我快速入门python看过的一些资料 B站的视频 10天自学Python,轻松掌握Python基础[千锋] 廖雪峰 - Python教程 https://www.liaoxuefeng.com/wik ...

  9. 5-4 Sentinel 限流_流控与降级

    Sentinel 介绍 什么是Sentinel Sentinel也是Spring Cloud Alibaba的组件 Sentinel英文翻译"哨兵\门卫" 随着微服务的流行,服务和 ...

  10. 【Codeforces1706A】 Another String Minimization Problem

    官方标签 贪心.字符串 题目描述 输入 输出 样例输入 6 4 5 1 1 3 1 1 5 2 4 1 1 1 1 1 2 4 1 3 2 7 7 5 4 5 5 5 3 5 样例输出 ABABA B ...