相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组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 }