有 (n) 个牧场,需要引水灌溉,第 (i) 号牧场挖井需要 (w_i),连接 (i,j) 的管道需要 (p_{i,j}),求对所有牧场实施灌溉的最小代价方案。(n leq 300)
Solution
难度:L2
设虚点 (n+1) 表示井水,然后连接所有边跑最小生成树即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 305;
int n,w[N],p[N][N],fa[N],ind;
struct edge {
int u,v,w;
bool operator < (const edge &b) {
return w<b.w;
}
} e[N*N*2];
int find(int p) {
return fa[p]==p?p:fa[p]=find(fa[p]);
}
void merge(int p,int q) {
p=find(p); q=find(q);
if(p!=q) fa[p]=q;
}
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n+1;i++) fa[i]=i;
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
cin>>p[i][j];
}
}
for(int i=1;i<=n;i++) e[++ind]={n+1,i,w[i]};
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
if(i==j) continue;
e[++ind]={i,j,p[i][j]};
}
}
sort(e+1,e+ind+1);
int ans=0;
for(int i=1;i<=ind;i++) {
edge &ed=e[i];
if(find(ed.u)!=find(ed.v)) {
ans+=ed.w;
merge(ed.u,ed.v);
}
}
cout<<ans;
}