hdu 3511

  题目意思实际上就是找嵌套数最大的圆并输出其嵌套数。

  一开始见时间有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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值