建图略巧妙…
新建一个点n+1,将所有点向该点连一条边,权值为建造水库的费用,然后问题等价于求该图的最小生成树.
AC code:
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=310;
const int M=100010;
int n,tot,ans;
int f[N];
struct Edge{
int u,v,w;
Edge() {}
Edge(int u,int v,int w):u(u),v(v),w(w) {}
friend bool operator<(Edge x,Edge y){
return x.w<y.w;
}
}E[M];
int find(int x){
return f[x]==x?x:f[x]=find(f[x]);
}
int main(){
scanf("%d",&n);
n++;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<n;i++){
int t;
scanf("%d",&t);
E[++tot]=Edge(i,n,t);
}
for(int i=1;i<n;i++){
for(int j=1;j<n;j++){
int t;
scanf("%d",&t);
if(i>=j) continue;
E[++tot]=Edge(i,j,t);
}
}
sort(E+1,E+tot+1);
for(int i=1;i<=tot;i++){
int u=E[i].u,v=E[i].v,w=E[i].w;
if(find(u)==find(v)) continue;
f[find(u)]=find(v);
ans+=w;
}
printf("%d\n",ans);
return 0;
}