1.prim算法
prim算法类似于dijkstra算法,我们先假设有一个最小生成树集合,都是被收录进来的结点,剩下的结点还没有被收录进来
每次都选择一个集合外,离集合最近的点,把它放入集合中,并且更新和他相邻的点到集合中的最小距离,便于下次使用
我们会发现,每个点被放入当前集合内的时候,都只会和集合内的一个顶点有弧,如果和两个顶点有弧,那么就构成了一个环,就不是最小生成树了
所以,每一个结点被放入集合中,都只会有一条直接相邻的边,共有n个结点,那么寻找最小边的操作只需要循环n次就可以了
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 505;
int e[N][N];
const int INF = 0x3f3f3f3f;
bool visit[N];
int n, m;
int dist[N];
typedef long long ll;
int prim()
{
ll res = 0;
int k = -1;
dist[1] = 0;
//先更新第一个点,起点
for (int i = 0;i < n;i++)
{
int v = -1;
int MIN = INF;
//下面是找到最小边的操作
for (int i = 0;i <= n;i++)
if (!visit[i] && dist[i] < MIN)
{
MIN = dist[i];
v = i;
}
//如果没找到,就直接return,说明这个不是一个连通图
if (v == -1) return INF;
res += dist[v]; //先在这里+上,不然可能有自边是负数,影响结果
//dist[v]表示到集合的最短距离,最小生成树就是记录每个点1到集合的最小距离
visit[v] = true; //表示已经访问了
for (int i = 1;i <= n;i++)
{
dist[i] = min(dist[i], e[v][i]);
//如果有自边是负数也不会影响最后的结果,因为他已经被放入集合中了
}
}
return res;
}
int main()
{
memset(dist, 0x3f, sizeof(dist));
memset(e, 0x3f, sizeof e);
cin >> n>>m;
for (int i = 0;i < m;i++)
{
int a, b,c;
cin >> a >> b >> c;
e[a][b] = e[b][a] = min(e[a][b], c);
}
int ans=prim();
if (ans==INF) cout << "impossible";
else cout << ans;
}
2.kruskal算法
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+10, M = 2 * N;//注意N要+5,防止出界
int dist[N];
const int INF = 0x3f3f3f3f;
struct node
{
int from;
int to;
int cost;
bool operator< (const node& W)const
{
return cost < W.cost;
}
}e[M];
int U[N];
int n, m;
int find(int x) //并查集
{
if (U[x] != x)
U[x] = find(U[x]);
return U[x];
}
int kruskal()
{/*kruskal算法,每次都选择最短的边看看是否能够放入(即是不是在一个集合中),
如果能够放入的话,就让他们并成一个集合,然后加上这条边的权重
注意的是,最小生成树的边==n-1条,如果<n-1,说明树没有联通
是不会大于n-1条边的,因为有并查集的存在*/
int cnt = 0;
int res = 0;
for (int i = 1;i<=n;i++)
U[i] = i;
for (int i = 0;i < m;i++)
{
int a = e[i].from;
int b = e[i].to;
int w = e[i].cost;
a = find(a), b = find(b);
if (a != b) //并查集,发现不是在一个集合内
{
U[a] = b;
res += w;
cnt++;
}
}
if (cnt < n - 1)return INF;
return res;
}
int main()
{
ios::sync_with_stdio(false); //输入数据大,需要加速
cin >> n >> m;
for (int i = 0;i < m;i++)
cin >> e[i].from>>e[i].to>>e[i].cost;
sort(e, e + m); //排序
int ans=kruskal();
if (ans == INF) cout << "impossible";
else cout << ans;
}