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. Luogu 3723 [AH2017/HNOI2017]礼物

    BZOJ 4827 $$\sum_{i = 1}^{n}(x_i - y_i + c)^2 = \sum_{i = 1}^{n}(x_i^2 + y_i^2 + c^2 - 2 * x_iy_i + ...

  2. Luogu 2886 [USACO07NOV]牛继电器Cow Relays

    BZOJ 1706权限题. 倍增$floyd$. 首先这道题有用的点最多只有$200$个,先离散化. 设$f_{p, i, j}$表示经过$2^p$条边从$i$到$j$的最短路,那么有转移$f_{p, ...

  3. rest 参数和扩展运算符

    rest 参数和扩展运算符 rest 参数的形式为 ...变量名:扩展运算符是三个点 .... rest 参数 function add(...values) { console.log(values ...

  4. PS插件开发plugin

    Photoshop插件开发 VC++制作Photoshop自动化插件:http://blog.sina.com.cn/s/blog_73c52fda0101c7hw.html Photoshop 的扩 ...

  5. 编写高质量代码改善C#程序的157个建议——建议58:用抛出异常代替返回错误代码

    建议58:用抛出异常代替返回错误代码 CLR异常机制的优点: 正常控制流会被立即中止,无效值或状态不会在系统中继续传播. 提供了统一的处理错误的方法. 提供了在构造函数.操作符重载及属性中报告异常的遍 ...

  6. sql 与 oracle 几个简单语法差别

    sql 与 oracle 之间的 语法差别. 简单的几个函数转换 sql->  Up_Time=getdate(),  isnull(), substring(),  charindex(), ...

  7. 前端框架 json 返回值

    layui: string strJson = "{\"code\": \"0\",\"msg\": \"\" ...

  8. ubuntu没有权限(不能)创建文件夹(目录)

    可以在终端直接运行 sudo nautilus,弹出来的nautilus可以直接GUI操作,中途别关终端.如果遇到需要输入root密码,则输入root密码就可以启动这个图形界面了.

  9. 通用唯一识别码——UUID(Python)

    一.概述: UUID(Universally Unique Identity)的缩写,是一种软件建构的标准,通常由32字节16进制数表示(128位),它可以保证时间和空间的唯一性.目前应用最广泛的UU ...

  10. 20165219 《Java程序设计》实验一(Java开发环境的熟悉)实验报告

    20165219 <Java程序设计>实验一(Java开发环境的熟悉)实验报告 一.实验报告封面 课程:Java程序设计 班级:1652班 姓名:王彦博 学号:20165219 成绩: 指 ...