省赛的时候没发现这道水题,发现了的话会毫不犹豫的上去写这道的,虽然估计也写不完,但至少算法是很清楚的。写完的时候都有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;
}
}