bzoj 1601 灌水

题目大意:

决定把水灌到n块农田,农田被数字1到n标记

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

建造一个水库需要花费wi,连接两块土地需要花费Pij. 计算所需的最少代价

思路:

新开一个节点与每个农田连一条长为wi的边

然后直接最小生成树

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 320
12 #define MOD 1000000007
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,cnt,fa[MAXN];
22 struct data 
23 {
24     int u,v,val;
25     bool operator < (const data &a) const
26     {
27         return val<a.val;
28     }
29 }e[MAXN*MAXN];
30 int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
31 bool ok(int u,int v) 
32 {
33     int fu=find(u),fv=find(v);
34     if(fu==fv) return 1;
35     else {fa[fu]=fv;return 0;}
36 }
37 void add(int u,int v,int w)  {e[++cnt].u=u,e[cnt].v=v,e[cnt].val=w;}
38 void kruskal()
39 {
40     sort(e+1,e+cnt+1);
41     int res=0,tot=0;
42     for(int i=1;i<=cnt;i++)
43     {
44         if(!ok(e[i].u,e[i].v)) res+=e[i].val,tot++;
45         if(tot==n) break;
46     }
47     printf("%d",res);
48 }
49 int main()
50 {
51     n=read();int a,b,c;
52     for(int i=1;i<=n;i++) {a=read(),fa[i]=i;add(i,n+1,a);}
53     for(int i=1;i<=n;i++)
54         for(int j=1;j<=n;j++)
55         {
56             a=read();
57             if(i!=j) add(i,j,a);
58         }
59     kruskal();
60 }
View Code

 

posted @ 2017-12-22 22:36  jack_yyc  阅读(109)  评论(0编辑  收藏  举报