题意:给定两堆点,问是否存在一个圆分开这两堆点。(使得一堆点在圆内或圆上,一堆点在圆外)
首先附英文官方题解: http://codeforces.com/blog/entry/18363 (弱鸡的我表示看不明白)
网上仅存的一篇题解,看得我是头皮发麻,表示看不懂- -;唉,还是太弱了。
没办法,只能自己硬啃AC代码。
现在整理一下思路:
首先我们要确定,如果存在一个圆将一堆点A包含在内,而另一堆点B在外的话,该圆的半径一定是大于或者等于这堆点A所确定的最小半径(可以理解为最小圆覆盖问题的那个半径),而且小于或者等于这堆点A所确定的最大半径的圆(最暴力的获得最大半径的做法:暴力枚举三个点,然后求半径【三点确定一个圆】,最大的那个值即最大半径,但是题目的数据范围显然不允许我们暴力解决问题)。
然后我们再确定一点,对于一堆在圆内的点,只有凸包上的点是有用的,凸包内的点此时可以忽略。所以这个问题我们需要求凸包,O(nlogn)级别的时间复杂度可以接受。
剩下的问题就是怎么高效地去寻找一个对应半径的圆,使得满足题意(又或者满足题意的圆不存在)。最最最暴力的方法:枚举三个点,求出这三个点确定的圆的半径,然后逐个逐个点判断是否满足题意,毫无疑问,时间复杂度绝对爆炸,但是最起码这是解决问题的一种思路,接下来我们就只需要利用一些操作去优化这个寻找的过程。
首先是高效地解决寻找圆的半径的问题:解决这类问题有一个思路,仔细观察,你会发现,每一个大问题,可以分解为两个较小的问题,(类似于二分),比如说:要求一堆点的最近点对,我们可以将这堆点从中间分成左右两部分,这样问题可以分解为求左半部分的最近点对和右半部分的最近点对,最后再比较合并(中间需要特殊处理,这里不详谈),然后最于每个子问题,也可以看成父问题一样去处理,这样一来本来需要O(n^2)时间复杂度的问题,就可以在O(nlogn)时间内解决(因为二分是O(logn)级别的),这种思想区别于二分,但本质差不多,叫做分治。
回到我们的问题,我们需要找到所有的半径,我们可以从大到小枚举。我们利用分治的思想,首先我们固定凸包上的两个端点,去枚举一个点,这样可以在O(n)时间复杂度求到一个最大半径,对于获得的最大半径,我们从最大半径处切开,分成两半,分别对这两半进行同样的操作,这样一来,我们就可以获得所有细分区域的最大半径(对于一堆点,要找一个最小覆盖圆,找的就是这个最大半径),然后我们对于每一个细分区域再进行对于圆外的点的比较操作。时间复杂度约等于O(nlogn),可以接受。
接下来就是还剩比较操作了,这一部分非常恶心,细节很多,稍微不注意就gg。详情看代码。
最后附AC代码:
//#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<stack>
#include<cstdio>
#include<queue>
#include<ctime>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define up(i,j,k) for(int i=j;i<k;i++)
#define uup(i,j,k) for(int i=j;i>=k;i--)
#define mem(i,j) memset(i,j,sizeof i)
#define sfi(i) scanf("%d",&i)
#define sfl(i) scanf("%lld",&i)
#define sfd(i) scanf("%lf",&i)
#define sfc(i) scanf("%c",&i)
#define sfs(i) scanf("%s",i)
#define sf() cout<<"This is a flag!"<<endl;
#define wt(i) cout<<"This is "<<i<<endl;
#define ll long long
#define mod(x) (x)%mod
#define fre() freopen("d:\\1.txt","r",stdin)
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x7f7f7f7f;
const int mod = 1e9 + 7;
const int MAX = 1e4 + 50;
const double dinf=0x7f7f7f7f7f7f7f7f7f7f7f7f7f7f;
int n,m;
struct node
{
double x,y;
}p[2][MAX],temp[MAX];
vector<node>pp[2];
double sqr(double xx)
{
return xx*xx;
}
double Get_Dis(const node &a,const node &b)
{
return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
double Cross(const node &p1,const node &p2,const node &p3)
{
double x1=p2.x-p1.x;
double y1=p2.y-p1.y;
double x2=p3.x-p1.x;
double y2=p3.y-p1.y;
return x1*y2-x2*y1;
}
int epss(const double xx)
{
if(fabs(xx)<eps)
return 0;
return xx>0?1:-1;
}
node mid;
bool cmp(const node &a,const node &b)
{
double C=Cross(mid,a,b);
if(epss(C)==0)
return Get_Dis(a,mid)<Get_Dis(b,mid);
if(epss(C)>0)
return true;
return false;
}
void Graham(int xx)
{
//pp[xx].clear();
mid=p[xx][0];
int nn;
if(xx==0)
nn=n;
else
nn=m;
if(nn<=2)
{
//sf();
up(i,0,nn)
{
pp[xx].push_back(p[xx][i]);
}
return;
}
int x=0;
up(i,1,nn)
{
if(epss(p[xx][i].y-mid.y)<0||epss(p[xx][i].y-mid.y)==0&&epss(p[xx][i].x-mid.x)<0)
{
mid=p[xx][i];
x=i;
}
}
swap(p[xx][x],p[xx][0]);
sort(p[xx]+1,p[xx]+nn,cmp);
temp[0]=p[xx][0];
temp[1]=p[xx][1];
//sf();
//cout<<p[xx][1].x<<' '<<p[xx][1].y<<endl;
int cnt=1;
up(i,2,nn)
{
//sf();
while(cnt&&epss(Cross(temp[cnt-1],temp[cnt],p[xx][i])<=0))
cnt--;
cnt++;
temp[cnt]=p[xx][i];
}
//cout<<cnt<<endl;
up(i,0,cnt+1)
{
pp[xx].push_back(temp[i]);
// cout<<temp[i].y<<endl;
}
return;
}
node Get_Center(const node &p1,const node &p2,const node &p3)
{
double a=p1.x-p2.x;
double b=p1.y-p2.y;
double c=p1.x-p3.x;
double d=p1.y-p3.y;
double e=((p1.x*p1.x-p2.x*p2.x)+(p1.y*p1.y-p2.y*p2.y))/2.0;
double f=((p1.x*p1.x-p3.x*p3.x)+(p1.y*p1.y-p3.y*p3.y))/2.0;
double det=b*c-a*d;
node Center;
Center.x=-(d*e-b*f)/det;
Center.y=-(a*f-c*e)/det;
return Center;
}
bool Judge_mid(const node &p1,const node &p2,const node &p3)
{
if(epss(p1.x-p2.x)==0)
{
if(epss(p1.y-p2.y)>0)
{
if(epss(p2.y-p3.y)>0)
{
return true;
}
return false;
}
else
{
if(epss(p2.y-p3.y)<0)
{
return true;
}
return false;
}
}
else
{
if(epss(p1.x-p2.x)>0)
{
if(epss(p2.x-p3.x)>0)
{
return true;
}
return false;
}
else
{
if(epss(p2.x-p3.x)<0)
{
return true;
}
return false;
}
}
}
bool Judge_Inside(int x1,int x2,int l,int r)
{
double LMAX=dinf,RMAX=-dinf;
int xx=-1;
bool flag=1,flagg=1;
up(i,l+1,r)
{
if(epss(Cross(pp[x1][l],pp[x1][r],pp[x1][i]))==0)
{
flag=0;
break;
}
node Center=Get_Center(pp[x1][l],pp[x1][r],pp[x1][i]);
mid.x=(pp[x1][l].x+pp[x1][r].x)/2.0;
mid.y=(pp[x1][l].y+pp[x1][r].y)/2.0;
double dis=Get_Dis(Center,mid);
if(epss(Cross(pp[x1][l],Center,pp[x1][r]))<0)
{
dis*=-1;
}
if(epss(dis-RMAX)>0)
{
RMAX=dis;
xx=i;
}
}
if(flag)
{
for(int i=(r+1)%pp[x1].size();i!=l;i=(i+1)%pp[x1].size())
{
if(epss(Cross(pp[x1][l],pp[x1][r],pp[x1][i]))==0)
{
flag=0;
break;
}
node Center=Get_Center(pp[x1][l],pp[x1][r],pp[x1][i]);
mid.x=(pp[x1][l].x+pp[x1][r].x)/2.0;
mid.y=(pp[x1][l].y+pp[x1][r].y)/2.0;
double dis=Get_Dis(mid,Center);
if(epss(Cross(pp[x1][l],Center,pp[x1][r]))<0)
{
dis*=-1;
}
if(epss(dis-LMAX)<0)
{
LMAX=dis;
}
}
}
// cout<<LMAX<<' '<<RMAX<<endl;
if(flag)
{
int tt=n;
if(x2==1)
tt=m;
up(i,0,tt)
{
if(epss(Cross(pp[x1][l],pp[x1][r],p[x2][i]))==0&&Judge_mid(pp[x1][l],p[x2][i],pp[x1][r]))
{
flagg=0;
break;
}
node Center=Get_Center(pp[x1][l],pp[x1][r],p[x2][i]);
mid.x=(pp[x1][l].x+pp[x1][r].x)/2.0;
mid.y=(pp[x1][l].y+pp[x1][r].y)/2.0;
double dis=Get_Dis(mid,Center);
//cout << pp[x1][l].x << ' ' << pp[x1][l].y << endl;
//cout << j << endl;
//if(j==1)
//cout << a[j - 1].x << ' ' << a[j - 1].y << endl;
//cout << pp[x1][r].x << ' ' << pp[x1][r].y << endl;
//cout << p[x2][i].x << ' ' << p[x2][i].y << endl;
//cout << "Circle:" << ' ' << Center.x << ' ' << Center.y << endl;
if (epss(Cross(pp[x1][l],Center,pp[x1][r])*epss(Cross(pp[x1][l],p[x2][i],pp[x1][r]))<0))
{
dis*=-1;
}
if (epss(Cross(pp[x1][l],p[x2][i],pp[x1][r]))>0)
{
if (epss(dis - LMAX)<0)LMAX = dis;
}
else if (epss(Cross(pp[x1][l],p[x2][i],pp[x1][r]))<0)
{
dis*=-1;
if (epss(RMAX - dis)<0)RMAX = dis;
}
if (epss(LMAX - RMAX) <= 0)
{
//cout<<111<<endl;
flagg=0;
break;
}
}
}
else
{
flagg=0;
}
//cout<<"xxxxx"<<' '<<xx<<endl;
if(flagg)
return true;
if(xx>=0)
{
return Judge_Inside(x1,x2,l,xx)||Judge_Inside(x1,x2,xx,r);
}
return false;
}
int main()
{
sfi(n);
sfi(m);
up(i,0,n)
{
sfd(p[0][i].x);
sfd(p[0][i].y);
}
up(i,0,m)
{
sfd(p[1][i].x);
sfd(p[1][i].y);
}
Graham(0);
Graham(1);
if(Judge_Inside(0,1,0,pp[0].size()-1))
{
printf("YES\n");
}
else if(Judge_Inside(1,0,0,pp[1].size()-1))
{
printf("YES\n");
}
else
{
printf("NO\n");
}
return 0;
}