畅通工程再续
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 20477 Accepted Submission(s): 6453
Problem Description
相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组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!
题目大意:
有n个岛屿,给出每个岛屿的坐标x,y,要在岛屿间建立连通的路,每米距离需花费100,现要使所有岛屿均连通,求最少花费。
题目分析:
本题先输入各桥坐标,通过各个岛的坐标我们可以计算出任意两个岛屿间的距离,然后使用两个for循环遍历出距每个岛距离最近的岛,将距离及岛屿编号i,j值存到一个结构体中,然后就可使用kruskal算法来求连通所有岛屿的最短路程,最后需加一个判断,判断是否连成一棵树,若是一棵树,则可以完成连通。
AC代码:
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
int per[110];
struct island{ //结构体来存放每个岛屿的坐标
double x,y;
}a[110];
struct node{ //用来存放两个岛屿间的距离,u、v间距离为w
int u,v;
double w;
}b[10010];
int cmp(node a,node b) //在排序时使用,将岛屿距离从小到大进行排序
{
return a.w<b.w;
}
double distance(double x1,double y1,double x2,double y2) //由两个岛屿的坐标计算距离
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int find(int x) //并查集的查找函数及压缩路径
{
int r=x;
while(r!=per[r])
r=per[r];
int j,i=x;
while(i!=r)
{
j=per[i];
per[i]=r;
i=j;
}
return r;
}
void join(int x,int y) //并查集的连接函数
{
int fx=find(x);
int fy=find(y);
if(fx!=fy) //此处是为了判断是否会成环
{
per[fx]=fy;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int flag=0;
int c,k=0;
scanf("%d",&c);
for(int i=1;i<=c;i++)
{
per[i]=i;
scanf("%lf%lf",&a[i].x,&a[i].y);
}
for(int i=1;i<c;i++)
{
for(int j=i+1;j<=c;j++)
{
double dis=distance(a[i].x,a[i].y,a[j].x,a[j].y);
if(dis>=10&&dis<=1000) //将任意两个岛屿间距离计算出来,若符合题目要求就存到结构体中
{
b[k].w=dis;
b[k].u=i;
b[k++].v=j;
}
}
}
if(k<c-1) //算是一个减枝吧,若可以连接的路径少于c-1条,则说明无法连通所有岛
{
printf("oh!\n");
continue;
}
sort(b,b+k,cmp); //对距离进行排序
double sum=0;
for(int i=0;i<k;i++)//使用kuskal算法找最小生成树
{
if(find(b[i].u)!=find(b[i].v))
{
join(b[i].u,b[i].v);
sum+=b[i].w; //sum是该最小生成树的最小距离
}
}
for(int i=1;i<=c;i++)
if(per[i]==i) //此步骤是对所有岛屿查找根节点,看是否连成一棵树
flag++;
if(flag==1) //若flag==1,说明只有一个根节点,说明连成了一棵树
printf("%.1lf\n",sum*100); //输出最少费用
else
printf("oh!\n"); //否则说明连成的不是一棵树
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。