起始思路:
我一开始看到题目,就想先用kruskal算法连成最小生成树,之后才是遍历并查集分情况讨论需要打多少口井,不谈能否做出,其实这个做法已经把问题复杂化了。
解题思路:
实际上,可以把所有未打的井看作一个公共的地下水源,所有农田到达这个水源的距离即为打井所消耗的距离,形成n+1个节点的经典并查集+kruskal算法解题的模板。
以下是题目:
代码:
#include <iostream>
using namespace std;
#include <vector>
vector<long long> v[100010];
long long fa[100005];
long long find(long long x){
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
int main(){
long long n;
cin>>n;
++n;
for(int i=1;i<=n;++i){
fa[i]=i;
}
for(int i=1;i<=n-1;++i){
long long tmp;
cin>>tmp;
v[tmp].push_back(i);
v[tmp].push_back(n);
}
for(int i=1;i<=n-1;++i){
for(int j=1;j<=n-1;++j){
long long tmp;
cin>>tmp;
if(j>i){
v[tmp].push_back(i);
v[tmp].push_back(j);
}
}
}
long long cnt=n,sum=0;
for(int i=0;i<100000;++i){
for(int j=v[i].size()-1;j>=1;j-=2){
long long fx=find(v[i][j]),fy=find(v[i][j-1]);
if(fx!=fy){
fa[fx]=fy;
sum+=i;
--cnt;
if(cnt==1){
cout<<sum<<endl;
return 0;
}
}
}
}
return 0;
}