已经有些边连通了,用并查集的话就是先把这些边union
了(记录conn
,不加opt
),再把未确定的边排序然后挨个union
;用prim
的话把这些边权值赋为0。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 1e2 + 5;
int N;
int pre[MAXN];
int conn;
int opt;
struct Edge
{
int n1, n2, w;
bool operator<(const Edge& e) const
{
return w < e.w;
}
};
vector<Edge> v;
int f(int x)
{
int f0 = x, f1 = x;
for (; pre[f0] > 0;)
{
f0 = pre[f0];
}
for (; pre[f1] > 0;)
{
int t = f1;
f1 = pre[f1];
pre[t] = f0;
}
return f0;
}
bool u(int a, int b)
{
int f1 = f(a);
int f2 = f(b);
if (f1 != f2)
{
conn++;
if (pre[f1] <= pre[f2])
{
pre[f1] += pre[f2];
pre[f2] = f1;
}
else
{
pre[f2] += pre[f1];
pre[f1] = f2;
}
return true;
}
return false;
}
int main()
{
int a, b, c, d;
for (; ~scanf("%d", &N);)
{
if (N == 0) return 0;
v.clear();
memset(pre, -1, sizeof pre);
conn = 0;
opt = 0;
for (int i = 0; i < N*(N - 1) / 2; i++)
{
scanf("%d%d%d%d", &a, &b, &c, &d);
if (d) u(a, b);
else v.push_back({ a,b,c });
}
sort(v.begin(), v.end());
for (int i = 0; i < v.size(); i++)
{
if (conn == N - 1) break;
if (u(v[i].n1, v[i].n2))
opt += v[i].w;
}
printf("%d\n", opt);
}
return 0;
}