不难看出这是一道最小生成树
but,我(蒟蒻)一开始以为是取最小的
v
[
i
]
v[i]
v[i]然后构建最小生成树
这样会有一个问题,建造电网有时候不一定会比建造电站更优
so~,我们可以把所有建电站的边连到一个虚点上,这样直接进行最小生成树就不会有问题了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 1e9 + 7;
const int N = 310000;
int n, v[N], f[N], ans;
struct Edge {
int to, nxt, val, from;
bool friend operator<(Edge x, Edge y) {
return x.val < y.val;
}
}edge[N << 1];
int head[N << 1], tot;
void add_edge(int x, int y, int z) {
edge[++tot].to = y;
edge[tot].from = x;
edge[tot].val = z;
edge[tot].nxt = head[x];
head[x] = tot;
}
inline int read () {
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int find(int x) {return f[x] == x ? f[x] : f[x] = find(f[x]);}
int main () {
scanf("%d", &n);
for(int i = 1; i <= n; i ++ ) v[i] = read();
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ )
add_edge(i, j, read());
for(int i = 1; i <= n; i ++ ) add_edge(i, n + 1, v[i]);
sort(edge + 1, edge + tot + 1);
for(int i = 1; i <= n + 1; i ++ ) f[i] = i;
for(int i = 1; i <= tot; i ++ ) {
int xx = edge[i].from, yy = edge[i].to;
int x = find(xx), y = find(yy);
if(x != y) {
ans += edge[i].val;
f[y] = x;
}
}
printf("%d\n", ans);
return 0;
}