UVA 4757 Open-air shopping malls

题目链接:http://livearchive.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2758

——————————————————————————————————————

题目描述:

平面上多个圆。现在要画一个大圆,使得该大圆的圆心在已给的任意一个圆的圆心上,且对于任何一个圆,该大圆都能至少覆盖到其面积的一半

——————————————————————————————————————

题目思路:

数据规模不大,枚举圆心,并扫描所有圆。用二分法判面积。

注意只有一个圆的情况

——————————————————————————————————————

源代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stack>

using namespace std;
#define INF 10000000
#define min(a,b) ((a)>(b)?(b):(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define maxn 110
const double pi = acos(-1.0);
const double eps = 1e-6;

typedef double T;

struct Pt
{
   T x;
   T y;
   int index;
   int flag;

   Pt(){}
   Pt(T px,T py) { x = px; y = py; }

   Pt operator +(const Pt &p) { return Pt(x+p.x,y+p.y); }
   Pt operator -(const Pt &p) { return Pt(x-p.x,y-p.y); }
   Pt operator * (double r){return Pt(x * r, y * r);}
   Pt operator / (double r){return Pt(x / r, y / r);}

   int operator ==(const Pt &p)
   {
       T temp = 0;
       temp = sqrt((x - p.x)*(x - p.x)+(y-p.y)*(y-p.y));

       if(temp<eps)
         return 1;
       else
         return 0;
   }
};

struct Line
{
    Pt a;
    Pt b;
    int num;

    Line(){}
    Line (Pt p1,Pt p2) { a = p1;  b = p2;}
};

//ab * cd
T dpr(Pt a,Pt b,Pt c,Pt d)  { return (b.x-a.x)*(d.x-c.x)+(b.y-a.y)*(d.y-c.y);}
T dpr_three(Pt a,Pt b,Pt c) { return (b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y);}

//ob × oc
T cpr(Pt a,Pt b,Pt c,Pt d){ return (b.x-a.x)*(d.y-c.y)-(b.y-a.y)*(d.x-c.x);}
T cpr_three(Pt o,Pt b,Pt c) { return (b.x-o.x)*(c.y-o.y)-(b.y-o.y)*(c.x-o.x);}

//a b为向量,向量的点积和叉积
T det(const Pt& a,const Pt& b) { return a.x*b.y - a.y*b.x; }
T dot(const Pt& a,const Pt& b) { return a.x*b.x + a.y*b.y; }

T d(Pt a,Pt b) { return sqrt((a.x - b.x)*(a.x - b.x) + (a.y-b.y)*(a.y - b.y));}

T sq(T x) {return x*x;}

//-------------符号函数--------------------
int sgn(T x) { return x<-eps?-1:x>eps;}

int epsfun(T x)
{
    if(x<-eps || x<eps)
      return 0;
    else
      return x;
}

//bool cmp(Line l1,Line l2) { return l1.a.x < l2.a.x; }
//bool cmp(Pt p1,Pt p2)
//{
 //    if(p1.y == p2.y) return p1.x<p2.x;
 //    return p1.y<p2.y;
//}

void judge_line(Line line1 ,Line line2)    //判断两直线位置关系并求交点
{
     if(sgn(cpr(line1.b,line1.a,line2.b,line2.a) == 0))
     {
        if(sgn(cpr(line1.b,line1.a,line2.b,line1.a) == 0))
          printf("LINE\n");
        else
          printf("NONE\n");
     }
     else
     {
        T s1 = cpr(line1.b,line1.a,line2.a,line1.a),s2 = cpr(line1.b,line1.a,line2.b,line1.a);
        printf("POINT ");
        printf("%.2f %.2f\n",(line2.a.x*s2-line2.b.x*s1)/(s2-s1),(line2.a.y*s2-line2.b.y*s1)/(s2-s1));
     }
}
//-------------直线线段相交--------------------
//直线与线段 规范相交: Line a为直线,Line b为线段
int line_seg_cross(Line a,Line b)
{
    if(sgn(cpr(a.b,a.a,b.a,a.a))*sgn(cpr(a.b,a.a,b.b,a.a))<0)
      return 1;
    else
      return 0;
}

int res_line_seg_cross()
{
   return 0;
}

//-------------线段线段相交--------------------
int between(Pt a,Pt b,Pt c)
{
    if(dpr_three(a,c,b)<=0)
      return 1;
    return 0;
}

//非规范相交(包括多个交点)
int segcross(Line linea,Line lineb)
{
    T s1 = 0,s2 = 0,s3 = 0,s4 = 0;
    int d1 = 0,d2 = 0,d3 = 0,d4 = 0 ;
    Pt a = linea.a,b = linea.b,c = lineb.a,d = lineb.b;

    d1 = sgn(s1 = cpr_three(a,b,c));
    d2 = sgn(s2 = cpr_three(a,b,d));
    d3 = sgn(s3 = cpr_three(c,d,a));
    d4 = sgn(s4 = cpr_three(c,d,b));

    if((d1^d2) == -2 && (d3^d4) == -2)  return 1;

    if((d1 == 0 && between(c,a,b)) || (d2 == 0 && between(d,a,b)) || (d3 == 0 && between(a,c,d)) || (d4 == 0 && between(b,c,d)))
        return 1;

    return 0;
}

//判规范相交
bool res_segcross(Line a,Line b)
{
    int d1 = sgn(det(a.a-b.a,b.b-b.a)),
        d2 = sgn(det(a.b-b.a,b.b-b.a)),
        d3 = sgn(det(b.a-a.a,a.b-a.a)),
        d4 = sgn(det(b.b-a.a,a.b-a.a));

    if (d1*d2 == -1 && d3*d4 == -1)
        return true;

    return false;
}

//规范相交:1, 非规范相交且交点有无数个:3 非规范相交且交点唯一:2  不相交:0

int segcross_all(Line linea,Line lineb,Pt *p)   //规范相交:1, 非规范相交且交点有无数个:3 非规范相交且交点唯一:2  不相交:0
{
    T s1 = 0,s2 = 0,s3 = 0,s4 = 0;
    int d1 = 0,d2 = 0,d3 = 0,d4 = 0 ;
    Pt a = linea.a,b = linea.b,c = lineb.a,d = lineb.b;

    d1 = sgn(s1 = cpr_three(a,b,c));
    d2 = sgn(s2 = cpr_three(a,b,d));
    d3 = sgn(s3 = cpr_three(c,d,a));
    d4 = sgn(s4 = cpr_three(c,d,b));

    if((d1^d2) == -2 && (d3^d4) == -2)
    {
        (*p).x = (c.x*s2 - d.x*s1)/(s2 - s1);
        (*p).y = (c.y*s2 - d.y*s1)/(s2 - s1);
        return 1;
    }
    if(!(d1 || d2 || d3 ||d4) && (between(c,a,b)||between(d,a,b)||between(a,c,d)||between(b,c,d)))
       return 3;

    if(d1 == 0 && between(c,a,b))
    {
        (*p).x = c.x;
        (*p).y = c.y;
        return 2;
    }
    if(d2 == 0 && between(d,a,b))
    {
        (*p).x = d.x;
        (*p).y = d.y;
        return 2;
    }
    if(d3 == 0 && between(a,c,d))
    {
        (*p).x = a.x;
        (*p).y = a.y;
        return 2;
    }
    if(d4 == 0 && between(b,c,d))
    {
        (*p).x = b.x;
        (*p).y = b.y;
        return 2;
    }

    return 0;
}

//------------------圆的运算-------------------
//两圆求交点
void intersection_circle_circle(Pt c1, double r1, Pt c2, double r2, Pt &p1, Pt &p2)
{
	double d2 = (c1.x - c2.x) * (c1.x - c2.x) + (c1.y - c2.y) * (c1.y - c2.y);
	double cos = (r1 * r1 + d2 - r2 * r2) / (2 * r1 * sqrt(d2));
	Pt v1 = (c2 - c1) / d(c1, c2), v2 = Pt(-v1.y, v1.x) * (r1 * sqrt(1 - cos * cos));
	Pt X = c1 + v1 * (r1 * cos);
	p1 = X + v2;
	p2 = X - v2;
}

//两圆位置关系:相离(包括外切)2 相交0 内含(包括内切)1
int circle_circle_sta(Pt o,T r1,Pt i,T r2)
{
    T dis = d(o,i);//d1 = sgn(d-r1+r2),d2 = sgn(d-r2+r1);

    //if((d1<0 || !d1) && (d>eps || a>b))

    if(dis<=fabs(r1-r2))
      return 1;
    if(dis>=r1+r2-eps)
      return 2;

    return 0;
}

//求两圆面积交
T circle_circle_intersect(Pt a,T ra,Pt b,T rb)
{
    T sa = sq(ra)*pi,sb = sq(rb)*pi;
    T dis = d(a,b);
    T anga = 0,angb = 0;

    anga = acos((sq(dis)+sq(ra)-sq(rb))/(2.0*ra*dis));
    angb = acos((sq(dis)+sq(rb)-sq(ra))/(2.0*rb*dis));

    return sa*anga/pi+sb*angb/pi-sin(2.0*anga)*sq(ra)/2.0-sin(2.0*angb)*sq(rb)/2.0;
}

Pt point[25];
T r[25],cur = 0;
int n = 0;

T update(int o,int i)
{
    T l = r[o],h = d(point[o],point[i])+r[i],m;
    T curs = 0,ss = sq(r[i])*pi;

    while(1)
    {
       m = (l+h)/2;
       if(circle_circle_sta(point[o],m,point[i],r[i]) == 1)
           h = m;
       else if(circle_circle_sta(point[o],m,point[i],r[i]) == 2)
           l = m;
       else
       {
          curs = circle_circle_intersect(point[o],m,point[i],r[i]);

          if(fabs(curs-ss/2.0)<eps)
            break;
          if(curs>ss/2.0)
            h = m;
          else
            l = m;
       }
    }
    return m;
}

void judge(int o,int i)
{
   int sta = 0;

   if(cur == -1)
   {
      cur = update(o,i);
      return;
   }
   sta = circle_circle_sta(point[o],cur,point[i],r[i]);
   if(sta == 1)
     return;

   if(sta == 2)
   {
      cur = update(o,i);
      return;
   }

   T temp = update(o,i);
   if(temp>cur)
     cur = temp;
   return;
}

int main()
{
   // freopen("in.in", "r", stdin);
   // freopen("out.txt","w",stdout);
   int t = 0;
   T x,y;
   int i = 0,j = 0;
   T bst = 0;

   scanf("%d",&t);
   while(t--)
   {
       scanf("%d",&n);

       for(i = 0;i<n;i++)
       {
           scanf("%lf%lf%lf",&x,&y,&r[i]);
           point[i] = Pt(x,y);
       }
       if(n == 1)
       {
          printf("%.4f\n",sqrt(2.0)*r[0]/2.0);
          continue;
       }

       bst = INF;
       for(i = 0;i<n;i++)
       {
          cur = -1;
          for(j = 0;j<n;j++)
          {
              if(i == j) continue;
              judge(i,j);
          }
          bst = min(bst,cur);
       }
       printf("%.4f\n",bst);
   }
   return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值