题目大意:
决定把水灌到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 }