【HDU-1875】畅通工程再续

86 阅读1分钟
题意

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

输入

输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。 每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。

输出

每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.

 

样例
Sample Input
2
2
10 10
20 20
3
1 1
2 2
1000 1000
 

Sample Output
1414.2
oh!

 



 

AC代码
/*
第一次提交:超时。将cin换成scanf
第二次:还是超时(怀疑是kruskal函数中的那个return)
第二次:还是超时(double换成float,结果报错)
最终的原因:edge数组开的太小了,因为他存储了100个点相互之间的关系!!!!!最多有100*(100-1)/2=5010
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int n,t,m,k;
int p[102];
struct Edge
{
  int u;
  int v;
  double w;
}edge[5010];
//因为最多有100个岛屿。故他们之间的相互关系最多有100*(100-1)/2=5010条,故这里定义数组的大小为5010就可以。如果少于5010,在oj上就会不对

//岛屿位置的结构体
struct Island
{
  double x;
  double y;
}island[102];

bool cmp(Edge a ,Edge b)
{
  return a.w<b.w;
}
int find(int x)
{
  return p[x]==x?x:x=find(p[x]);
}

//基于并查集的克鲁斯卡尔算法
void kruskal()
{
  for(int i=0;i<n;i++)
  {
    p[i]=i;
  }
  sort(edge,edge+k,cmp);
  int num=0;
  double ans=0;
  for(int i=0;i<k;i++)
  {

      //产看这两个岛屿是否已经在一个集合里
      int p1=find(edge[i].u);
      int p2=find(edge[i].v);
      if(p1!=p2)
	  {
	    ans+=edge[i].w;  //把连接两个集合的路径长度加上
	    p[p1]=find(p2);  //合并岛屿
	    num++;  //记录合并动作的次数
	  }

	  //如果所有的分散岛屿到最后合并成了一个,则说明连通了
	  //因为共有n个岛屿,所以最多只能合并n-1次,而当合并了n-1次的时候,就说明整个森林肯定都连通了。所以,m=n-1时就已经可以输出最后结果了
	  if(num==n-1)
      {
          printf("%.1lf\n",ans*100);
          return;  //函数返回,从main函数中执行下一个测试样例
      }
  }
  printf("oh!\n");
}
int main()
{
    //freopen("input.txt", "r", stdin);
	cin>>t;
	while(t--)
	{
	  cin>>n;
	  //二维坐标点用结构体存储
	  for(int i=0;i<n;i++)
	  {
	      cin>>island[i].x>>island[i].y;
	  }
	  //计算各个岛屿相互之间的距离。如果不用k只用i,j作为edge的下标,则很难做到“相互”
	  //并且图是对称的,仅保存一半即可
	  k=0;
      for(int i=0;i<n;i++)
      {
          for(int j=i+1;j<n;j++)
          {
              double instance=sqrt((island[i].x-island[j].x)*(island[i].x-island[j].x)+(island[i].y-island[j].y)*(island[i].y-island[j].y));//使用pow函数精确度不对。标准为什么
              //如果距离不符合规范,则不进行保存
              //u代表某个岛屿的起点,v代表终点,两道与之间路径的长度未w
              if(instance>=10&&instance<=1000)
              {
                edge[k].u=i;
                edge[k].v=j;
                edge[k].w=instance;
                k++;
              }
           }
      }
	  kruskal();
	}
	return 0;
}

 

题源:acm.hdu.edu.cn/showproblem…