写在前面的话
本算法与 D i j k s t r a Dijkstra Dijkstra算法原理几乎相同,若有对Dijkstra不了解的朋友,可以先了解一下,这样看这篇文章会轻松很多。
如果你没有了解过该算法也没关系,以我的讲解的详细程度,你也一定能明白的 希望吧
代码
朴素版
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510, INF = 1e9;
int n, m; //点数、边数
int dist[N], g[N][N]; //g:邻接矩阵;dist:到一点最短边的权值
bool st[N]; //某点是否被考虑过
int prim()
{
memset(dist, 0x3f, sizeof(dist));
int res = 0; //权值之和
for(int i = 0; i < n; i++)
{
int t = -1; //-1表示尚未考虑任何点
for(int j = 1; j <= n; j++)
{
if(!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
//找边权最小的点、且没有被考虑过的点
}
if(i && dist[t] == INF) return INF;
//若边权最小的点为正无穷,则判定改图不连通
if(i) res += dist[t];
st[t] = true; //更改边权总和并将该点标记为“已考虑”
for(int j = 1; j <= n; j++) //松弛操作
{
dist[j] = min(dist[j], g[t][j]);
}
}
return res;
}
int main()
{
cin >> n >> m;
memset(g, 0x3f, sizeof(g));
for(int i = 1; i <= n; i++) g[i][i] = 0;
for(int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
g[u][v] = min(g[u][v], w);
g[v][u] = min(g[v][u], w);
}
//输入、初始化(这个要是都看不明白,还是先把基础语法学扎实吧)
int t = prim();
if(t >= INF) cout << "impossible"; //图不连通
else cout << t; //边权总和
return 0;
}
以上为朴素版代码以及注释。
优化版
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int N = 510, INF = 1e9;
typedef pair<int, int> PII;
int n, m;
int dist[N];
bool st[N];
vector<PII> g[N];
int prim()
{
memset(dist, 0x3f, sizeof(dist));
priority_queue<PII, vector<PII>, greater<PII> > q;
q.push({0, 1});
int res = 0, cnt = 0;
while(q.size())
{
PII t = q.top(); q.pop();
int idx = t.second, w = t.first;
if(st[idx]) continue;
/*
t目前为权值最小的边的权值以及顶点
if一句为判断该边是否被考虑过。
·如果是,则continue,因为此方法一定不是该顶点的最优解。
·否则,标记之,并更新相关的顶点的距离。
*/
st[idx] = true;
cnt++; //统计已经考虑过的点数(判断图是否连通)
res += w; //边权之和
for(int i = 0; i < g[idx].size(); i++) //松弛
{
int tw = g[idx][i].first, tv = g[idx][i].second;
if(dist[tv] > tw)
{
dist[tv] = tw;
q.push({dist[tv], tv});
}
}
}
if(cnt < n) return INF;
return res;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
if(u == v) continue;
g[u].push_back({w, v});
g[v].push_back({w, u});
}
int t = prim();
if(t >= INF) cout << "impossible";
else cout << t;
return 0;
}
如果你已经理解了朴素版或Dijkstra的优化版,那么这上述内容对你来说一定小菜一碟。
解析
说实话,我感觉真没什么可讲的了。注释打得很清楚了。
提供一道例题:模板:最小生成树
尾声
写的怎么样: