题目意思实际上就是找嵌套数最大的圆并输出其嵌套数。
一开始见时间有5000ms,就果断暴力,然后果断超时— — 之后用二分,终于不tle啦,但wa。。。TAT。上网找题解,发现有两种方法,一个是用随机数,另一个是计算几何中的扫描法,其中用了set,没见过,于是好好学习了一下,发现思想还是很好懂的,该解法的所在地址是:
http://hi.baidu.com/bobobry/blog/item/e270bf097b3bd9376b60fbbe.html
以下是计算几何的解法:
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<set>
#include<cmath>
using namespace std;
const int M=50100;
int max(int a,int b) {return a>b?a:b;}
int n,t;
struct cirs
{
int x,y;
int r,w;
}cir[M];
struct event
{
int x;
int id,mark; //mark为1,则圆为运算对象,反之,圆要删出set
}eve[2*M];
int nowx;
double cacul(int id,int mark)
{
double d;
d=sqrt((double)cir[id].r*cir[id].r-(double)(nowx-cir[id].x)*(nowx-cir[id].x));
return mark?(double)cir[id].y+d:(double)cir[id].y-d;
}
bool equal(double a,double b)
{
if(fabs(a-b)<1e-8) return 1;
else return 0;
}
struct nodes
{
int id;
int mark;
bool operator<(const nodes a)const //set的<要重载
{
double y1=cacul(id,mark);
double y2=cacul(a.id,a.mark);
return y1>y2 || equal(y1,y2) && mark>a.mark;
}
};
set<nodes> line;
set<nodes>::iterator it,pre,succ;
int cmp(const void *a,const void *b)
{
int t;
struct event *x,*y;
x=(struct event *)a;
y=(struct event *)b;
t=x->x-y->x;
if(t!=0) return t;
else t=cir[y->id].y-cir[x->id].y;
return t;
}
void move_line() //计算几何中的扫描法
{
line.clear();
int i,j;
for(i=0;i<t;i++)
{
nowx=eve[i].x;
if(eve[i].mark==1) //这个圆没运算过
{
struct nodes node;
node.id=eve[i].id;
node.mark=1;
it=line.insert(node).first;
succ=pre=it;
succ++;
if(it==line.begin() || succ==line.end())
{
cir[it->id].w=1; //此时是最外层的圆
}
else //当前圆嵌套与前一个圆中
{
pre--;
if(pre->id==succ->id)
{
cir[it->id].w=cir[pre->id].w+1;
}
else //处于同一嵌套级别的圆的嵌套数
{
cir[it->id].w=max(cir[pre->id].w,cir[succ->id].w);
}
}
struct nodes node2;
node2.id=eve[i].id;
node2.mark=0;
line.insert(node2).second;
}
else //该圆的右点以被扫描到,该离开set了
{
struct nodes node,node2;
node.id=eve[i].id;
node.mark=1;
line.erase(node);
node2.mark=0;
node2.id=eve[i].id;
line.erase(node2);
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
int i,j;
while(scanf("%d",&n)==1)
{
t=0;
for(i=0;i<n;i++)
{
scanf("%d%d%d",&cir[i].x,&cir[i].y,&cir[i].r);
cir[i].w=0;
eve[t].x=cir[i].x-cir[i].r;
eve[t].id=i;
eve[t].mark=1;
t++;
eve[t].x=cir[i].x+cir[i].r;
eve[t].id=i;
eve[t].mark=0;
t++;
}
qsort(eve,t,sizeof(eve[0]),cmp);
move_line();
int ans=-1;
for(i=0;i<n;i++)
{
if(cir[i].w>ans)
ans=cir[i].w;
}
printf("%d\n",ans);
}
return 0;
}
接下的这份随机函数的代码就真的很考验rp的哈,我交了8次才过了3次。。。两次是直接拿那位大牛的来交的。。。。
#include<cstdio>
#include<cstring>
#include <cstdlib>
#include<ctime>
#include<iostream>
using namespace std;
const int M=50000;
struct cir
{
double x,y,r;
}c[M];
bool vis[M];
int n;
int main()
{
srand((unsigned)time(NULL));
while(scanf("%d",&n)==1)
{
int i,j,ans=-1;
for(i=0;i<n;i++)
scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].r);
memset(vis,0,sizeof(vis));
int tmp=1;
for(j=1;j<n;j++)
{
if((c[0].x-c[j].x)*(c[0].x-c[j].x)+(c[0].y-c[j].y)*(c[0].y-c[j].y)<c[j].r*c[j].r)
tmp++;
}
if(tmp>ans) tmp=ans;
int rd;
for(i=0;i<n && i<5000 && ans!=n;)
{
rd=rand()%n;
if(vis[rd]) continue;
vis[rd]=1;
i++;
tmp=1;
for(j=0;j<n;j++)
{
if(rd==j) continue;
if((c[rd].x-c[j].x)*(c[rd].x-c[j].x)+(c[rd].y-c[j].y)*(c[rd].y-c[j].y)<c[j].r*c[j].r)
tmp++;
}
if(tmp>ans) ans=tmp;
}
printf("%d\n",ans);
}
return 0;
}