185. [USACO Oct08] 挖水井
185. [USACO Oct08] 挖水井
输入文件:water.in 输出文件:water.out 简单对比
时间限制:1 s 内存限制:128 MB
农夫约翰决定给他的N(1<=N<=300)个牧场浇水,这些牧场被自然的命为1..N。他可以给一个牧场引入水通过在这个牧场挖一口井或者修一条管道使这个牧场和一个已经有水的牧场连接。
在牧场i挖一口井的花费是w_i(1<=w_i<=100000)。修建一条水管连接牧场i和牧场j的花费是p_ij(1<=p_ij<=100000;p_ij=p_ji;p_ii=0)。
请确定农夫约翰为了完成浇灌所有的牧场所需的最小的总花费。
题目名称:water
输入格式:
第1行:一个单独的整数n。
第2..n+1行:第i+1行包含一个单独的整数w_i。
第n+2..2n+1行:第n+1+i行包含n个用空可分开的整数;其中第j个数是p_ij。
输入样例(file water.in):
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
输入说明:
这里有4个牧场,修井和修管道的代价如图。
输出格式:
第1行:一个单独的整数,表示花费。
输出样例(file water.out):
9
输出说明:
农夫约翰可以在第4个牧场修井,并且将每个牧场和第一个连接起来,这样,花费是3+2+2+2=9。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn=100001; 7 int dad[maxn],n,m,u,v,w,b[maxn],tot,q,k,x; 8 9 struct Zb{ 10 int x;int y;int w; 11 }a[maxn]; 12 13 int find(int x){//找父亲 14 if(x!=dad[x]) dad[x]=find(dad[x]); 15 return dad[x]; 16 } 17 18 void unionn(int x,int y){//找祖先,合并为同一祖先 19 int r1=find(x); 20 int r2=find(y); 21 if(r1!=r2) 22 dad[r1]=r2; 23 } 24 25 int cmp(const Zb &a,const Zb &b){//排序 26 if(a.w<b.w) return 1; 27 return 0; 28 } 29 30 int main() 31 { 32 freopen("water.in","r",stdin); 33 freopen("water.out","w",stdout); 34 cin>>n; 35 for(int i=1;i<=n;i++){ 36 cin>>b[i]; 37 } 38 for(int i=1;i<=n;i++) dad[i]=i; 39 for(int i=1;i<=n;++i) 40 { 41 for(int j=1;j<=n;++j){ 42 cin>>x; 43 if(x!=0){//将x所代表的连通的点记录下来 44 m++;//记录有几个点是连通的 45 a[m].x=i,a[m].y=j,a[m].w=x; 46 } 47 } 48 } 49 for(int i=1;i<=n;i++)//将需要挖井的费用加入 50 { 51 m++; 52 a[m].x=i; 53 a[m].y=n+1; 54 a[m].w=b[i]; 55 m++; 56 a[m].x=n+1; 57 a[m].y=i; 58 a[m].w=b[i]; 59 } 60 sort(a+1,a+m+1,cmp);//将树从小到大排序 61 k=0; 62 for(int i=1;i<=m;i++){ 63 if(find(a[i].x)!=find(a[i].y)) 64 { 65 unionn(a[i].x,a[i].y); 66 tot+=a[i].w;//总费用 67 k++; 68 } 69 if(k==n) break;//当找完所有点的时候,退出 70 } 71 cout<<tot<<endl; 72 fclose(stdin);fclose(stdout); 73 return 0; 74 }