掌握魔法の东东 I
作者:互联网
题解:
东东在老家农村无聊,想种田。农田有 n 块,编号从 1~n。种田要灌氵
众所周知东东是一个魔法师,他可以消耗一定的 MP 在一块田上施展魔法,使得黄河之水天上来。他也可以消耗一定的 MP 在两块田的渠上建立传送门,使得这块田引用那块有水的田的水。 (1<=n<=3e2)
黄河之水天上来的消耗是 Wi,i 是农田编号 (1<=Wi<=1e5)
建立传送门的消耗是 Pij,i、j 是农田编号 (1<= Pij <=1e5, Pij = Pji, Pii =0)
东东为所有的田灌氵的最小消耗
Input
第1行:一个数n
第2行到第n+1行:数wi
第n+2行到第2n+1行:矩阵即pij矩阵
Output
东东最小消耗的MP值
Example
Input
4 5 4 4 3 0 2 2 2 2 0 3 3 2 3 0 4 2 3 4 0Output
9
我的题解:
如果忽略天上水,则为最小生成树为题,那么,我们怎么解决这添上水呢?
事实上,如果把它当成一个超级原点(连接所有其他点)的话,问题就转化成了我们熟悉的最小生成树问题!
最小生成树我采用kruskal的方法,每次从中选取(合法的)最小边。
判断成环与否我们用并查集思想:两端点如果不属于一个集合,那么证明添加后不会成环。
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 int par[310], rnk[310],nums=0; 5 typedef struct node{ 6 int u,v,w; 7 bool operator<(node &edg){ 8 return w<edg.w; 9 } 10 }Edge; 11 12 Edge Edges[100000]; 13 14 int find(int x) 15 { return par[x]==x? x : par[x]=find(par[x]);} 16 17 bool unite(int x,int y){ 18 x=find(x);y=find(y); 19 if(x==y) return false; 20 if(rnk[x]>rnk[y]) swap(x,y); 21 par[x]=y; rnk[y] += rnk[x]; 22 return true; 23 } 24 25 int main(){ 26 int n;cin>>n; 27 for(int i=0;i<n+1;i++){ 28 par[i]=i; 29 rnk[i]=1; 30 } 31 int w; 32 for(int i=0;i<n;i++){ 33 cin>>w; 34 Edges[nums].u=0; 35 Edges[nums].v=i+1; 36 Edges[nums++].w=w; 37 } 38 for(int i=0;i<n;i++){ 39 for(int j=0;j<n;j++){ 40 cin>>w; 41 if(i!=j) 42 { 43 Edges[nums].u=i+1; 44 Edges[nums].v=j+1; 45 Edges[nums++].w=w; 46 } 47 } 48 } 49 sort(Edges,Edges+nums); 50 int sum=0,cnt=0; 51 for(int i=0;i<nums;i++){ 52 if(unite(Edges[i].u,Edges[i].v)){ 53 sum+=Edges[i].w; 54 cnt++; 55 } 56 if(cnt==n) break; 57 } 58 cout<<sum<<endl; 59 return 0; 60 }
标签:nums,int,东东,魔法,最小,消耗,Edges,掌握 来源: https://www.cnblogs.com/liuzhuan-xingyun/p/12624384.html