Lego Bricks [2011 浙江省赛I题] 计算几何

来源:互联网 发布:网络钓鱼常用的手段是 编辑:程序博客网 时间:2024/04/30 06:16

 

省赛的时候没发现这道水题,发现了的话会毫不犹豫的上去写这道的,虽然估计也写不完,但至少算法是很清楚的。写完的时候都有300来行了= =!

题意:

给定n个园和m个线段,初始圆已经被固定住,要求把m个线段放上去,能否使m个线段都被固定。如果有线段已经被固定,这可以用这些线段来固定剩下的线段。

题解:

被固定的意思显然是重心被支撑住,可以有一半以上架在圆上,或者两端都有支撑点。

转化成算法就是把线段平均分成两段,如果两段都能被固定则整个线段是能被固定的。

要用到圆跟线段相交判定与线段与线段相交判定。

线段判定:http://blog.csdn.net/SwordHoly/archive/2011/03/30/6289952.aspx

圆跟线段相交判定:http://blog.csdn.net/tiaotiaoyly/archive/2008/03/28/2226597.aspx

代码:

#include<iostream>

#include "math.h"  

#include<memory.h>

using namespace std;

#define EPS 0.00001

struct pt   

{  

    float x;  

    float y;    

    pt() {} 

    pt(float m, float n) : x(m),y(n)  {}

};  

struct circle

{

pt ptCenter;

double Radius;

};

struct Segment

{

pt a,b;

};

int n,m; 

circle c[1005];

Segment s[1005];

bool is_balanced[1005];

double min(double x,double y)

{

if (x<y) return x;

else return y;

}

double max(double x,double y)

{

if (x>y) return y;

else return x;

}

 

double Cross(pt a,pt b)

 

{

 

    return a.x*b.y-a.y*b.x;

 

}

 

double  Cross(pt a,pt b,pt c)

 

{

 

    return Cross(pt(a.x-c.x,a.y-c.y),pt(b.x-c.x,b.y-c.y));

 

}

 

pt intersection(pt u1,pt u2,pt v1,pt v2)

 

{

 

    pt ret=u1;

 

    double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x));

 

    double tt=((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));

 

    ret.x=ret.x*tt+(u2.x-u1.x)*t;

 

    ret.y=ret.y*tt+(u2.y-u1.y)*t;

 

   // ret.tt=tt;

 

    return ret;

 

}

 

 bool same_side(pt p1,pt p2,pt l1,pt l2)//p1或p2落在直线上就算异面

 {

 

     double c1=Cross(l1,p1,l2),c2=Cross(l1,p2,l2);

 

     if (c1>0) c1=1;

 

     if (c1<0) c1=-1;

 

     if (c2>0) c2=1;

 

     if (c2<0) c2=-1;

 

   return (c1*c2>0);

 

 }

bool SegCross(Segment a,Segment b)

{

      pt u1=a.a,u2=a.b,v1=b.a,v2=b.b;

      int flag;

        if (u1.x>u2.x) {pt t=u1;u1=u2;u2=t;}

 

        if (v1.x>v2.x) {pt t=v1;v1=v2;v2=t;}

 

        flag=-1;

 

        //u is a pt

 

        if ( (u1.x==u2.x)&&(u1.y==u2.y) )

 

        {

 

            if ((Cross(u1,v1,v2)==0)&&(u1.x>=v1.x)&&(u1.x<=v2.x)&&(u1.y>=min(v1.y,v2.y))&&(u1.y<=max(v2.y,v1.y)) )//第一次这里漏了,没判断y方向的

 

            {

 

                flag=1;

 

               // res=u1;

 

            }

 

            else

 

                flag=0;

 

        }

 

        //v is a pt

 

          if ( (v1.x==v2.x)&&(v1.y==v2.y) )

 

        {

 

            if ((Cross(v1,u1,u2)==0)&&(v1.x>=u1.x)&&(v1.x<=u2.x)&&(v1.y>=min(u1.y,u2.y))&&(v1.y<=max(u2.y,u1.y)))

 

            {

 

                flag=1;

 

               // res=v1;

 

            }

 

            else

 

                flag=0;

 

        }

 

        if (flag==-1)

 

       if ((Cross(u1,v1,v2)==0)&&(Cross(u2,v1,v2)==0) )//在同一直线上

 

        {

 

            if (u1.x!=u2.x)//不垂直

 

            {

 

                if (v1.x==u2.x)

 

                {

 

                    flag=1;

 

                  //  res=u2;

 

                }

 

                else if (v1.x>u2.x)

 

                {

 

                    flag=0;

 

                }

 

                else

 

                {

 

                    if (v2.x==u1.x)

 

                    {

 

                        flag=1;

 

//                        res=v2;

 

                    }

 

                    else if(v2.x<u1.x)

 

                    {

 

                        flag=0;

 

                    }

 

                    else

 

                    {

 

                        flag=2;

 

                    }

 

                }

 

            }

 

            else

 

            {

 

                     if (u1.y>u2.y) {pt t=u1;u1=u2;u2=t;}

 

                     if (v1.y>v2.y) {pt t=v1;v1=v2;v2=t;}

 

                if (v1.y==u2.y)

 

                {

 

                    flag=1;

 

                  //  res=u2;

 

                }

 

                else if (v1.y>u2.y)

 

                {

 

                    flag=0;

 

                }

 

                else

 

                {

 

                    if (v2.y==u1.y)

 

                    {

 

                        flag=1;

 

             //           res=v2;

 

                    }

 

                    else if(v2.y<u1.y)

 

                    {

 

                        flag=0;

 

                    }

 

                    else

 

                    {

 

                        flag=2;

 

                    }

 

                }

 

            }

 

        }

 

        else

 

        {

 

             if ( (!same_side(u1,u2,v1,v2))&&(!same_side(v1,v2,u1,u2)) )

 

            {

 

                flag=1;

 

               // res=intersection(u1,u2,v1,v2);

 

            }

 

            else flag=0;

 

        }

  if (flag>0) return true;

  else return false;

 

pt p1,p2;

double dis(pt a,pt b){

    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));

}

double dot(pt p1,pt p2,pt p0){

    return (p1.x-p0.x)*(p2.x-p0.x) + (p1.y-p0.y)*(p2.y-p0.y);

}

double mul(pt p1,pt p2,pt p0){

    return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);

}

double Min(double a,double b){

    return a>b?b:a;

}

double Abs(double a){

    return a>0?a:-a;

}

double disline(pt a,pt b,pt p){

    if(dot(a,b,p)<0)  return Abs(mul(b,p,a))/dis(a,b);

    else return Min(dis(a,p),dis(b,p));

}

bool SegCircleCross(pt a,pt b,pt cir,double r)

{

pt c;

c.x=(a.x+b.x)/2.;

    c.y=(a.y+b.y)/2.;

    bool flag,fl,fr; 

flag=fl=fr=0;

if(dis(c,cir)<=r) flag=1;

    if(disline(a,c,cir)<=r) fl=1;

    if(disline(c,b,cir)<=r) fr=1;

            if(fl||fr) flag=1;

return flag;

}

int main()

{

int i,j,tcase,u;

cin>>tcase;

while(tcase--)

{

       cin>>n>>m;

  for(i=1;i<=n;i++)

  cin>>c[i].ptCenter.x>>c[i].ptCenter.y>>c[i].Radius;

  for(i=1;i<=m;i++)

  cin>>s[i].a.x>>s[i].a.y>>s[i].b.x>>s[i].b.y;

  memset(is_balanced,0,sizeof(is_balanced));

  for(u=1;u<=m;u++)

  {

  bool fl=false;

            for(i=1;i<=m;i++)

if (!is_balanced[i])

{

Segment l,r;

bool is_l,is_r;

l.a=s[i].a;l.b.x=(s[i].a.x+s[i].b.x)/2;l.b.y=(s[i].a.y+s[i].b.y)/2;

r.a=l.b;r.b=s[i].b;

is_l=is_r=false;

for(j=1;j<=n;j++)

{

if (SegCircleCross(l.a,l.b,c[j].ptCenter,c[j].Radius)) is_l=true;

if (SegCircleCross(r.a,r.b,c[j].ptCenter,c[j].Radius)) is_r=true;

}

for(j=1;j<=m;j++)

                     if (is_balanced[j])

{

if  (SegCross(l,s[j]))

is_l=true;

if (SegCross(r,s[j]))

is_r=true;

}

if (is_l&&is_r) {is_balanced[i]=true;fl=true;}

}

if (!fl) break;

  }

  int ans=0;

  for(i=1;i<=m;i++)

  ans+=is_balanced[i];

  if (ans==m) cout<<"YES"<<endl;

  else cout<<"NO"<<endl;

}

}

 

 

 

原创粉丝点击