BZOJ 1601 [Usaco2008 Oct]灌水:最小生成树

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1601

题意:

  Farmer John已经决定把水灌到他的n(1<=n<=300)块农田,农田被数字1到n标记。

  把一块土地进行灌水有两种方法,从其他农田饮水,或者这块土地建造水库。

  建造一个水库需要花费wi(1<=wi<=100000),连接两块土地需要花费P[i][j](1 <= p[i][j] <= 100000, p[i][j]=p[j][i], p[i][i]=0)。

  计算Farmer John所需的最少代价。

 

题解:

  农田标号1到n,建立超级源点为0号点。

  从超级源点向每个农田连一条长度为w[i]的边。然后n个农田之间再互相连接,边长为p[i][j]。

  然后求最小生成树就好。

 

AC Code:

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <algorithm>
  5 #include <vector>
  6 #define MAX_N 305
  7 
  8 using namespace std;
  9 
 10 struct Edge
 11 {
 12     int sour;
 13     int dest;
 14     int len;
 15     Edge(int _sour,int _dest,int _len)
 16     {
 17         sour=_sour;
 18         dest=_dest;
 19         len=_len;
 20     }
 21     Edge(){}
 22     friend bool operator < (const Edge &a,const Edge &b)
 23     {
 24         return a.len<b.len;
 25     }
 26 };
 27 
 28 int n;
 29 int ans;
 30 int par[MAX_N];
 31 vector<Edge> edge;
 32 
 33 void init_union_find()
 34 {
 35     for(int i=0;i<=n;i++)
 36     {
 37         par[i]=i;
 38     }
 39 }
 40 
 41 int find(int x)
 42 {
 43     return par[x]==x?x:par[x]=find(par[x]);
 44 }
 45 
 46 void unite(int x,int y)
 47 {
 48     int px=find(x);
 49     int py=find(y);
 50     if(px==py) return;
 51     par[px]=py;
 52 }
 53 
 54 bool same(int x,int y)
 55 {
 56     return find(x)==find(y);
 57 }
 58 
 59 int kruskal()
 60 {
 61     init_union_find();
 62     sort(edge.begin(),edge.end());
 63     int cnt=0;
 64     int res=0;
 65     for(int i=0;i<edge.size();i++)
 66     {
 67         Edge temp=edge[i];
 68         if(!same(temp.sour,temp.dest))
 69         {
 70             cnt++;
 71             res+=temp.len;
 72             unite(temp.sour,temp.dest);
 73         }
 74     }
 75     return cnt==n?res:-1;
 76 }
 77 
 78 void read()
 79 {
 80     cin>>n;
 81     int a;
 82     for(int i=1;i<=n;i++)
 83     {
 84         cin>>a;
 85         edge.push_back(Edge(0,i,a));
 86     }
 87     for(int i=1;i<=n;i++)
 88     {
 89         for(int j=1;j<=n;j++)
 90         {
 91             cin>>a;
 92             if(i<j) edge.push_back(Edge(i,j,a));
 93         }
 94     }
 95 }
 96 
 97 void solve()
 98 {
 99     ans=kruskal();
100 }
101 
102 void print()
103 {
104     cout<<ans<<endl;
105 }
106 
107 int main()
108 {
109     read();
110     solve();
111     print();
112 }

 

posted @ 2017-10-03 11:09  Leohh  阅读(163)  评论(0编辑  收藏  举报