题意
传送门 POJ 2421
题解
K r u s k a l Kruskal Kruskal 基本思路是边按权值排序,从小到大查看一遍,若加入图中不产生圈,则把当前边加入树中。那么对于已连通的节点,先用并查集维护,最后跑 K r u s k a l Kruskal Kruskal 即可。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 105
struct edge
{
int u, v, cost;
edge() {}
edge(int u, int v, int cost) : u(u), v(v), cost(cost) {}
} es[maxn * maxn / 2];
int n, q, e;
int par[maxn], rnk[maxn];
void init(int n)
{
for (int i = 1; i <= n; i++)
{
par[i] = i, rnk[i] = 0;
}
}
int find(int x)
{
return par[x] == x ? x : (par[x] = find(par[x]));
}
bool same(int x, int y)
{
return find(x) == find(y);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y)
return;
if (rnk[x] > rnk[y])
par[y] = x;
else
{
par[x] = y;
if (rnk[x] == rnk[y])
++rnk[y];
}
}
bool cmp(const edge &e1, const edge &e2)
{
return e1.cost < e2.cost;
}
int kruskal()
{
sort(es, es + e, cmp);
int res = 0;
for (int i = 0; i < e; i++)
{
edge &ee = es[i];
if (!same(ee.u, ee.v))
{
unite(ee.u, ee.v);
res += ee.cost;
}
}
return res;
}
int main()
{
while (~scanf("%d", &n))
{
init(n);
e = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
int c;
scanf("%d", &c);
if (j > i)
{
es[e++] = edge(i, j, c);
}
}
}
scanf("%d", &q);
while (q--)
{
int a, b;
scanf("%d%d", &a, &b);
unite(a, b);
}
printf("%d\n", kruskal());
}
return 0;
}