[USACO08OCT] Watering Hole G
题目描述
Farmer John 的农场缺水了。
他决定将水引入到他的 n n n 个农场。他准备通过挖若干井,并在各块田中修筑水道来连通各块田地以供水。在第 i i i 号田中挖一口井需要花费 W i W_i Wi 元。连接 i i i 号田与 j j j 号田需要 P i , j P_{i,j} Pi,j( P j , i = P i , j P_{j,i}=P_{i,j} Pj,i=Pi,j)元。
请求出 FJ 需要为使所有农场都与有水的农场相连或拥有水井所需要的最少钱数。
输入格式
第一行为一个整数 n n n。
接下来 n n n 行,每行一个整数 W i W_i Wi。
接下来 n n n 行,每行 n n n 个整数,第 i i i 行的第 j j j 个数表示连接 i i i 号田和 j j j 号田需要的费用 P i , j P_{i,j} Pi,j。
输出格式
输出最小开销。
样例 #1
样例输入 #1
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
样例输出 #1
9
提示
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 300 1 \leq n \leq 300 1≤n≤300, 1 ≤ W i ≤ 1 0 5 1 \leq W_i \leq 10^5 1≤Wi≤105, 0 ≤ P i , j ≤ 1 0 5 0 \leq P_{i,j} \leq 10^5 0≤Pi,j≤105。
思路
因为本道题有点权还有边权两个自变量,而且这两个自变量没有任何关系,因此我们可以考虑将点权转化为边权,总结:点权转化为边权的方法是:建立超级原点,因此,本道题我们可以通过建立超级原点来进行kruskal
代码
//对于这样点权转化为边权,常常可建立个超级原点
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 300010;
struct E{
int x,y,w;
}e[N];
int p[N];
int w[N];
int n,cnt;
int find(int x){
if(x!=p[x])p[x]=find(p[x]);
return p[x];
}
void kurskal(){
int res=0;
for(int i=0;i<cnt;i++){
int pa=find(e[i].x),pb=find(e[i].y);
if(pa!=pb){
p[pa]=pb;
res+=e[i].w;
}
}
cout<<res;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
p[i]=i;
cin>>w[i];
e[cnt++]={0,i,w[i]};
e[cnt++]={i,0,w[i]};
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int x;
cin>>x;
if(i!=j)e[cnt++]={i,j,x};
}
}
sort(e,e+cnt,[&](E a,E b){
return a.w<b.w;
});
kurskal();
return 0;
}