题目要求:万湖之国的形成
时间限制:10000MS 内存限制:65535K
提交次数:0 通过次数:0
语言:G++;GCC;VC
描述
N国原是一块平原上,没有湖,直到一颗小行星撞入大气层碎成成千上万的碎片,碎片再撞击地面形成
一个一个的坑, 下雨之后,最终形成万湖之国。
现在科学家想用计算机模拟万湖之国形成过程,假设每一块碎片撞击地面,都撞出一个园形坑,现在知道
每一个碎片造成的坑的圆心和半径,问每个坑都注满水后,最终形成多少个湖?
输入格式
第一行一个整数N,1<=N<=100,000,表示坑的数量
此后N行,每一行三个double实数,前两个数是圆心的坐标x和y,最后一个数是圆半径(不大于1000)
(数据随机产生,分布均匀)
分析:将题目中提及的坑抽象出来就是探讨圆与圆之间的关系,统计所有相交圆和内含圆的个数,然后用总圆个数减去相交圆和内含圆的个数即是题目中要求的湖的个数。所以现在的关键点转化成了求非相交圆和非内含圆的个数,但由于数据的产生是随机的,所以对于圆与圆之间的关系判断就变得比较复杂。不过,它数据产生是随机的,我们可以人为地让它变成不随机的。判断的复杂性主要是由于其大小我们难以预测,那我们就可以先给数据排个序,然后判断一个圆跟坐标在它前面的圆是否相交或内含,但一个圆跟另一个圆有交集时,我们将其归为一类,这里引入一种数据结构叫并查集,主要功能是将数据归类,最后统计总共有多少类就可以知道总共有多少个湖了。在C++中,我们用图来实现并查集。(当然你也可以用数组等其他结构来表示,只是用图可能会更加方便一些。)具体实现如下:
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll; //结果可能过大,所以要用long long,这里typedef是为了方便后面写代码
map<ll,ll>fa; //存储圆的类
struct g //定义圆
{
double x,y,r;
bool operator <(const g b) const //定义圆比较的方法
{
return x+r<b.x+b.r;
}
}a[100050]; //存储数据
ll findset(int i) //若圆相交或内含,则归为一类
{
if(fa[i]==i) return i;
return fa[i]=findset(fa[i]);
}
int main()
{
int n,m;
cin>>n;
m=n;
for(int i=0;i<n;i++)
{
cin>>a[i].x>>a[i].y>>a[i].r;
fa[i]=i;
}
sort(a,a+n);
for(int i=0;i<n;i++)
{
for(int j=i-1;j>=0;j--)
{
if(a[j].x+a[j].r<=a[i].x-a[i].r) break;
if((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)<(a[i].r+a[j].r)*(a[i].r+a[j].r))
{
ll l=findset(i),r=findset(j);
if(fa[l]!=r) m--;
fa[l]=r;
}
}
}
cout<<m<<endl;
return 0;
}