题意:还是给你n个点,然后求最小生成树。特殊之处在于有一些点之间已经连上了边
最小生成树直接做
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define maxn 200009
using namespace std;
int n, m, a[109][109], head[109], next[1009], to[1009], tot = 1, vis[109], belong[109];
int rev[109], dist[109][109], father[109], cnt = 0;
vector <int> point;
void down (int &x, int y)
{
if (y < x)
x = y;
}
void add (int x, int y)
{
to[++tot] = y;
next[tot] = head[x];
head[x] = tot;
}
struct cadongllas
{
int x, y, value;
}edge[100009];
bool cmp (cadongllas x, cadongllas y)
{
return x.value < y.value;
}
void dfs (int x, int y)
{
vis[x] = 1;
belong[x] = y;
for (int i = head[x]; i; i = next[i])
if (!vis[to[i]])
dfs (to[i], y);
}
int get_father (int x)
{
if (father[x] == x)
return x;
return get_father (father[x]);
}
int main()
{
cin >> n;
rep (i, 1, n)
rep (j, 1, n)
scanf ("%d", &a[i][j]);
cin >> m;
int x, y;
rep (i, 1, m)
scanf ("%d%d", &x, &y), add (x, y), add (y, x);
rep (i, 1, n)
if (!vis[i])
dfs (i, i), point.push_back (i);
int t = point.size ();
rep (i, 0, t - 1)
rev[point[i]] = i;
rep (i, 0, t - 1)
rep (j, 0, t - 1)
dist[i][j] = dist[j][i] = a[point[i]][point[j]];
rep (i, 1, n)
rep (j, 1, n)
down (dist[ rev[belong[i]] ][ rev[belong[j]] ], a[i][j]), down (dist[ rev[belong[j]]][ rev[belong[j]] ], a[i][j]);
rep (i, 0, t - 1)
father[i] = i;
rep (i, 0, t - 1)
rep (j, 0, t - 1)
if (i != j)
edge[++cnt] = (cadongllas){i, j, dist[i][j]};
sort (edge + 1, edge + 1 + cnt, cmp);
int ans = 0;
rep (i, 1, cnt)
{
int u = get_father (edge[i].x), v = get_father (edge[i].y);
if (u != v)
father[u] = v, ans += edge[i].value;
}
cout << ans << endl;
return 0;
}