トピック:ポータル
プリムアルゴリズム
アイデア:
配列を使用して、各ポイントから最小スパニングツリーが配置されているセットまでの最小距離を記録します。最小距離のポイントが選択されてその距離でセットに結合され、そのポイントが更新に使用されるたびに他のポイントの距離。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5010, M = 200010;
int g[N][N], res, n, m;
int dis[N]; // dis[i]:当前使得第i个点加入集合的最小距离
bool in[N]; // 记录当前点是否被加入集合
bool prim()
{
memset(dis, 0x3f, sizeof dis);
dis[1] = 0;
for (int i = 1; i <= n; i++)
{
int t = -1;
for(int j = 1; j <= n; j++)
if(!in[j] && (t == -1 || dis[t] > dis[j])) t = j;
if (dis[t] == 0x3f3f3f3f) return false; // 若所有未加入集合的点到集合的距离均为无穷大,则不存在最小生成树
res += dis[t];
in[t] = true;
for(int j = 1; j <= n; j++)
dis[j] = min(dis[j], g[t][j]);
}
return true;
}
int main()
{
memset(g, 0x3f, sizeof g);
cin >> n >> m;
int x, y, z;
for(int i = 0; i < m; i++)
{
cin >> x >> y >> z;
g[y][x] = g[x][y] = min(g[x][y], z);
}
if(prim()) cout << res;
else cout << "orz";
return 0;
}
クラスカルアルゴリズム
アイデア:
すべてのエッジを重みに従って小さいものから大きいものへと並べ替えてから、各エッジをトラバースし、組み合わせた検索を使用して、エッジの左右の端点が同じセットに属しているかどうかを判断します。最小スパニングツリーのエッジ、そして最後に左右のエンドポイントが配置されているセットがマージされます。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5010, M = 200010;
int f[N];
int n, m;
struct edge
{
int a, b, w;
bool operator < (const edge & t)
{
return w < t.w;
}
}edges[M];
inline int find(int x)
{
if(x != f[x]) f[x] = find(f[x]);
return f[x];
}
int main()
{
cin >> n >> m;
int x, y, z;
for(int i = 0; i < m; i++)
{
cin >> x >> y >> z;
edges[i] = {
x, y, z};
}
sort(edges, edges+m);
for (int i = 1; i <= n; i++) f[i] = i;
int cnt = 0, ans = 0;
for(int i = 0; i < m; i++)
{
int a = edges[i].a, b = edges[i].b, w = edges[i].w;
a = find(a), b = find(b);
if( a!= b)
{
cnt++;
ans += w;
f[a] = b;
}
}
if(cnt < n - 1) cout << "orz"; //仅当合并次数为n-1次,所有点才处于同集合中,否则最小生成树不存在
else cout << ans;
return 0;
}