kruskal算法和prim算法

都说 kruskal是加边法,prim是加点法

这篇解释也不错:这篇

1、kruskal算法

  因为是加边法,所以这个方法比较合适稀疏图。要码这个需要先懂并查集。因为我不会画好看的图,所以看不懂的话推荐下面博客的说明。这里是下面

步骤:

1、把每个点都看成一棵树,那么你就会得到一片森林。。。

2、把每棵树之间的距离从小到大排序,即把边排序

3、从小到大取边,把不在同一棵树的点连通到同一棵树上。。。最后你会得到一棵树,就是最小生成树

我去盗图。。。这里的图

给个模板题吧。。HDU1233

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) struct Edge
{
int u, v, w;
bool operator < (const Edge &a) const
{
return w < a.w;
}
}edge[MAXN];
int n, ans, fa[]; //找父节点并压缩路径,这是并查集的知识
int Get_f(int x)
{
if(fa[x] == x)
return x;
return fa[x] = Get_f(fa[x]);
} void Kruskal()
{
//初始化
for(int i = ;i <= n;++i)
fa[i] = i;
sort(edge, edge + (n - ) * n / );
ans = ; int x, y, cnt = ;
for(int i = ;i < n * (n - ) / ;++i)
{
x = Get_f(edge[i].u), y = Get_f(edge[i].v);
//加边
if(x != y)
{
ans += edge[i].w;
fa[x] = y;
cnt++;
}
//加入所有点了
if(cnt >= n)
break;
}
printf("%d\n", ans);
} int main()
{
while(scanf("%d", &n) != EOF && n)
{
for(int i = ;i < n * (n - ) / ;++i)
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
Kruskal();
}
return ;
}

2、Prim算法

  这算法写起来跟最短路的 Dijkstra算法很像。来复习一下 Dijkstra算法,先找出距离源点最短的点(这里是找出离一个点最近的路),然后把这个点与。源点连接(这里是连接这两个点),之后再更新最短路(更新到各个点的最短的边,这里代码有点不同)。。。就没有哈哈哈哈。。。直接上上面那道模板题代码吧。。。。。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) int mp[MAXN][MAXN], dis[MAXN], n, ans;
bool vis[MAXN]; void Prim(int s)
{
Mem0(vis);
int i, j;
for(i = ;i <= n;++i)
dis[i] = mp[s][i];
dis[s] = ;
int v, w;
vis[s] = true;
for(i = ;i < n;++i)
{
w = INF;
for(j = ;j <= n;++j)
{
if(!vis[j] && dis[j] < w)
{
w = dis[j];
v = j;
}
}
vis[v] = true;
ans += w;
for(j = ;j <= n;++j)
if(!vis[j] && dis[j] > mp[v][j])//这里不同
dis[j] = mp[v][j];
}
printf("%d\n", ans);
} int main()
{
int a, b, c;
while(scanf("%d", &n) != EOF && n)
{
MemM(mp);
ans = ;
for(int i = ;i < n * (n - ) / ;++i)
{
scanf("%d%d%d", &a, &b, &c);
mp[a][b] = mp[b][a] = c;
}
Prim();
}
return ;
}

3、 STL与kruskal(理论上 Prim算法应该能用优先队列简化找最短路径的操作,就。。不码这个了)

用map存边,简化排序操作。。。先是模板题练练手,可是跑出来时间慢了十几毫秒

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) int ans, n, fa[MAXN];
int Get_F(int x)
{
if(fa[x] == x)
return x;
return fa[x] = Get_F(fa[x]);
} int main()
{
while(scanf("%d", &n) != EOF && n)
{
ans = ;
multimap<int, pair<int, int> > mp;
for(int i = ;i <= n;++i)
fa[i] = i;
int a, b, c;
for(int i = ;i < n * (n - ) / ;++i)
{
scanf("%d%d%d", &a, &b, &c);
mp.insert(make_pair(c, make_pair(a, b)));
}
multimap<int, pair<int, int> > :: iterator it;
int x, y;
for(it = mp.begin();it != mp.end();++it)
{
x = Get_F((*it).second.first), y = Get_F((*it).second.second);
if(x != y)
{
fa[x] = y;
ans += (*it).first;
}
}
printf("%d\n", ans);
}
return ;
}

再给多一道题 UVALive - 6437,先用Prim写一下,感觉Prim比较容易理解,然后再用 kruskal写个简单版的。

Prim思路:。。。。下面注释吧。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) //点数 n,边数 m ,发电站数量 num, 图 mp, 发电站 power
int ans, n, m, num, vis[MAXN], dis[MAXN], mp[MAXN][MAXN];
int power[MAXN];
int Prim()
{
int i, j, k;
// 各个城镇到各个发电站的最短距离
MemM(dis);
for(i = ;i <= n;++i)
for(j = ;j < num;++j)
dis[i] = min(dis[i], mp[i][power[j]]);
int w, v;
// 还要对 n - num 个点找最短路
for(i = ;i < n - num;++i)
{
w = INF;
for(j = ;j <= n;++j)
if(!vis[j] && dis[j] < w)
{
w = dis[j];
v = j;
}
vis[v] = true;
ans += w;
// 这里可以理解为城镇新建了发电站,就看其他城镇到这个新发电站的距离
for(j = ;j <= n;++j)
if(!vis[j] && dis[j] > mp[v][j])
dis[j] = mp[v][j];
}
return ans;
} int main()
{
int T;
scanf("%d", &T);
for(int cas = ;cas <= T;++cas)
{
MemM(mp);
Mem0(vis);
ans = ;
scanf("%d%d%d", &n, &m, &num);
for(int i = ;i <= n;++i)
mp[i][i] = ;
int a, b, c;
for(int i = ;i < num;++i)
{
scanf("%d", &power[i]);
vis[power[i]] = true;//这里先处理发电站比较方便
}
for(int i = ;i < m;++i)
{
scanf("%d%d%d", &a, &b, &c);
mp[a][b] = mp[b][a] = c;
}
printf("Case #%d: %d\n", cas, Prim());
}
return ;
}

Kruskal。。。这道题把所有发电站都先放到一个集合里,那么最后出来的最小生成树就是答案了。。。。具体点就是把所有发电站的祖先都设为同一个,这样不管连接哪一个发电站都有共同祖先。

慢了30ms左右

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) int ans, n, m, k, fa[MAXN];
int Get_F(int x)
{
if(fa[x] == x)
return x;
return fa[x] = Get_F(fa[x]);
} int main()
{
int T;
scanf("%d", &T);
for(int cas = ;cas <= T;++cas)
{
multimap<int, pair<int, int> > mp;
multimap<int, pair<int, int> > :: iterator it;
ans = ;
scanf("%d%d%d", &n, &m, &k);
for(int i = ;i <= n;++i)
fa[i] = i;
int a, b, c;
//处理发电站
scanf("%d", &a);
for(int i = ;i < k;++i)
{
scanf("%d", &b);
fa[b] = a;
}
for(int i = ;i < m;++i)
{
scanf("%d%d%d", &a, &b, &c);
mp.insert(make_pair(c, make_pair(a, b)));
}
ans = ;
int x, y;
for(it = mp.begin();it != mp.end();++it)
{
x = Get_F((*it).second.first), y = Get_F((*it).second.second);
if(x != y)
{
ans += (*it).first;
fa[x] = y;
}
}
printf("Case #%d: %d\n", cas, ans);
}
return ;
}
 

最小生成树的kruskal、prim算法的更多相关文章

  1. 最小生成树(Kruskal+Prim)--模板

    最小生成树-----在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树. 应用场景 1.假设以下情景,有一块木板,板上钉上了一些钉子,这些钉子可以由一些细绳连接起来.假设每个钉子可以通 ...

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

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

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

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

  4. 数据结构之最小生成树Prim算法

    普里姆算法介绍 普里姆(Prim)算法,是用来求加权连通图的最小生成树算法 基本思想:对于图G而言,V是所有顶点的集合:现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T存放G的最 ...

  5. POJ-3026(图上的最小生成树+prim算法+gets函数使用)

    Borg Maze POJ-3026 一开始看到这题是没有思路的,看了题解才知道和最小生成树有关系. 题目的意思是每次走到一个A或者S就可以分为多个部分继续进行搜索.这里就可以看出是从该点分出去的不同 ...

  6. MAT之prim算法

    prim算法 边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1 ...

  7. Prim算法(普里姆算法)

    描述: 一个连通图的生成树是指一个极小连通子图,它含有图中的全部顶点,但只有足以构成一棵树的 n-1 条边.我们把构造连通网的最小代价生成树成为最小生成树.而Prim算法就是构造最小生成树的一种算法. ...

  8. 数据结构与算法系列研究七——图、prim算法、dijkstra算法

    图.prim算法.dijkstra算法 1. 图的定义 图(Graph)可以简单表示为G=<V, E>,其中V称为顶点(vertex)集合,E称为边(edge)集合.图论中的图(graph ...

  9. 贪心算法-最小生成树Kruskal算法和Prim算法

    Kruskal算法: 不断地选择未被选中的边中权重最轻且不会形成环的一条. 简单的理解: 不停地循环,每一次都寻找两个顶点,这两个顶点不在同一个真子集里,且边上的权值最小. 把找到的这两个顶点联合起来 ...

  10. 最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind

    最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小 ...

随机推荐

  1. ubuntu下安装配置apache2(含虚拟主机配置)

    在Ubuntu14.14中安装apache 安装指令: sudo apt-get install apache2 安装结束后: 产生的启动和停止文件是: /etc/init.d/apache2 启动: ...

  2. laravel的orm增删改查

    增: //通过模型新增 //使用模型的create方法新增数据 删: //通过模型删除 //通过主键删除 改: //通过模型更新数据库 //结合查询语句批量更新 查:

  3. C# 世界坐标 页面坐标 PageUnit PageScale

    PageScale:  获取或设置此 Graphics 的世界单位和页单位之间的比例.PageUnit:  获取或设置用于此 Graphics 中的页坐标的度量单位. 话不多说,上代码: privat ...

  4. 如何处理与开发有争议的Bug?

     工作中,测试人员有时会遇到类似的问题:提交了一份软件缺陷报告,可由于某种原因,无论是开发人员还是开发经理就是不愿修改程序.应如何处理这类问题呢?我认为,当对报告出现分歧意见后,测试工程师应首先做如下 ...

  5. javascript高级程序设计读书笔记----函数表达式

    定义函数两种方式: 1.函数声明 function sayHi(){ alert("Hi"); } sayHi();//调用函数 2.函数表达式 var sayHi = funct ...

  6. MVPArms MVP快速集成框架

    前言 今年的Android技术圈中MVP,Dagger2,Rxjava,Retrofit这些词汇非常火,随便打开一个技术论坛都充斥着大量的关于这些技术的文章,Github也充斥着各种以基于MVP+Re ...

  7. JMeter的使用——ApacheJMeterTemporaryRootCA.crt的用法

    在使用JMeter的时候,启动HTTP代理服务器弹出的那个提示框一直不知道是什么意思,刚刚弄明白了,在JMeter2.1之后,通过JMeter的代理服务器来访问https安全连接的网页的时候,浏览器会 ...

  8. 正确处理类的复合关系------新标准c++程序设计

    假设要编写一个小区养狗管理程序,该程序需要一个“主人”类,还需要一个“狗”类.狗是有主人的,主人也有狗.假定狗只有一个主人,但一个主人可以有最多10条狗.该如何处理“主人”类和“狗”类的关系呢?下面是 ...

  9. web.xml报错:cvc-complex-type.2.4.a: Invalid content was found starting with element 'async-supported'. One of '{"http://java.sun.com/xml/ns/javaee":init-param}' is expected.

    在写xml的时候又一次总是报cvc-complex-type.2.4.a: Invalid content was found starting with element 错误,还出现小红叉,在网上找 ...

  10. Thread Group(线程组)

    线程组,可以理解用户池,用来产生线程(用户),每一个线程代表一个用户,在使用JMeter进行性能测试过程中,经常需要模拟多个用户进行测试,可以通过设置线程数代表多少个用户,通常一个线程组就代表一个测试 ...