畅通工程再续 HDU - 1875 最小生成树之Kruskal算法

相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。

Input输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。 
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。 
Output每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.Sample Input

2
2
10 10
20 20
3
1 1
2 2
1000 1000

Sample Output

1414.2
oh!

思路:先把点的坐标信息转换成点与点之间的距离,然后容最小生成树的算法连接所有的岛屿,注意连接岛屿的限制,最后再判断是否连接了所有的的岛屿,再输出结果

代码:
  1 #include <cstdio>
  2 #include <fstream>
  3 #include <algorithm>
  4 #include <cmath>
  5 #include <deque>
  6 #include <vector>
  7 #include <queue>
  8 #include <string>
  9 #include <cstring>
 10 #include <map>
 11 #include <stack>
 12 #include <set>
 13 #include <sstream>
 14 #include <iostream>
 15 #define mod 998244353
 16 #define eps 1e-6
 17 #define ll long long
 18 #define INF 0x3f3f3f3f
 19 using namespace std;
 20 /*
 21 //存放地图
 22 int ma[100][100];
 23 //lowcost存放到起点的距离
 24 //mst表示i指向的点,
 25 int lowcost[100],mst[100];
 26 //n表示点数
 27 int n;
 28 //初始化地图
 29 void init()
 30 {
 31     for(int i=0;i<=n;i++)
 32     {
 33         for(int j=0;j<=n;j++)
 34         {
 35             //本地到本地的权值为0,到其他点的权值为无穷
 36             if(i==j)
 37             {
 38                 ma[i][j]=0;
 39             }
 40             else
 41             {
 42                 ma[i][j]=INF;
 43             }
 44         }
 45     }
 46 }
 47 //u表示起点
 48 int prim(int u)
 49 {
 50     //ans表示树上所有边的权值和
 51     int ans=0;
 52     //初始化lowcost,mst
 53     for(int i=1;i<=n;i++)
 54     {
 55         //将所有指向起点的边录入lowcost中
 56         lowcost[i] = ma[u][i];
 57         //所有的点都指向起点
 58         mst[i]=u;
 59     }
 60     //起点已在树上,所以为-1
 61     mst[u] = -1;
 62     //遍历其他n-1个点
 63     for(int i=1;i<n;i++)
 64     {
 65         //当前最小权值为INF
 66         int mi=INF;
 67         //当前最小值指向的点是-1
 68         int v=-1;
 69         //遍历所有的点
 70         for(int j=1;j<=n;j++)
 71         {
 72             //如果该点不在树上,且该点到起点的距离小于当前最小权值
 73             if(mst[j]!=-1&&lowcost[j]<mi)
 74             {
 75                 //记录这个较小的点和权值
 76                 v=j;
 77                 mi=lowcost[j];
 78             }
 79         }
 80         //v!=-1表示在所有与树连接的最小权值
 81         if(v!=-1)
 82         {
 83             //将这个点标记
 84             mst[v]=-1;
 85             //累计这个边的权值
 86             ans+=lowcost[v];
 87             //遍所有的点
 88             for(int j=1;j<=n;j++)
 89             {
 90                 //如果j不在树上且j到树上的距离比j到v的距离大
 91                 //更新这个数据,并将mst[j]指向v
 92                 if(mst[j]!=-1&&lowcost[j]>ma[v][j])
 93                 {
 94                     lowcost[j]=ma[v][j];
 95                     mst[j]=v;
 96                 }
 97             }
 98         }
 99     }
100     //返回树上所有边的权值和
101     return ans;
102 }
103 */
104 //u表示起点,v表示终点,cost表示花费
105 struct node
106 {
107     int u,v;
108     double cost;
109     bool operator < (const node & p) const {
110         return cost < p.cost;
111     }
112 };
113 //存放边的信息
114 vector<node> ve;
115 int n;
116 //fa表示当前i的最远祖先
117 int fa[110];
118 //初始化fa,开始时自己是自己的祖先
119 void init(int qwq)
120 {
121     for(int i=0;i<=qwq;i++)
122     {
123         fa[i]=i;
124     }
125 }
126 //查找最远祖先,同时进行路径压缩
127 int find(int x)
128 {
129     if(fa[x]==x)
130     {
131         return x;
132     }
133     return fa[x]=find(fa[x]);
134 }
135 //判断最远祖先是否相同
136 bool che(int x,int y)
137 {
138     return find(x)==find(y);
139 }
140 //合并x,y,把他们放到同一个家族中
141 void mer(int x,int y)
142 {
143     if(!che(x,y)) 
144     {
145         fa[fa[x]]=fa[y];
146     }
147     return ;
148 }
149 //保存点的信息
150 struct dian
151 {
152     int x,y;
153 };
154 dian di[105];
155 //求点与点之间的距离
156 double distan(dian a,dian b)
157 {
158     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
159 }
160 
161 int main()
162 {
163     scanf("%d",&n);
164     while(n--)
165     {
166         int m;
167         scanf("%d",&m);
168         //初始化
169         init(m);
170         for(int i=0;i<m;i++)
171         {
172             scanf("%d %d",&di[i].x,&di[i].y);
173         }
174         node no;
175         //将点的坐标转换成点与点之间的距离并存入容器中
176         for(int i=0;i<m-1;i++)
177         {
178             for(int j=i+1;j<m;j++)
179             {
180                 no.u=i;
181                 no.v=j;
182                 no.cost=distan(di[i],di[j]);
183                 ve.push_back(no);
184             }
185         }
186         //排序
187         sort(ve.begin(),ve.end());
188         //ans表示树上边的权值总和
189         double ans=0;
190         //js表示连接的边数
191         int js=0;
192         for(int i=0;i<ve.size();i++)
193         {
194             //但两个点不在一个集合中且这两个点之间的距离能够建桥时连接他们
195             if(!che(ve[i].u,ve[i].v)&&ve[i].cost>=10&&ve[i].cost<=1000)
196             {
197                 mer(ve[i].u,ve[i].v);
198                 ans+=ve[i].cost;
199                 js++;
200             }
201             //如果连接了m-1条边则所有的点都已经连载一起了,不需要再循环了
202             if(js==m-1)
203             {
204                 break;
205             }
206         }
207         //如果连接了m-1条边则表示所有的点已连接否则无法全部畅通
208         if(js==m-1)
209         {
210             printf("%.1lf\n",ans*100);
211         }
212         else
213         {
214             printf("oh!\n");
215         }
216         //清除容器的内存
217         ve.clear();
218     }
219 }

猜你喜欢

转载自www.cnblogs.com/mzchuan/p/11747167.html
今日推荐