Codeforces 549E Sasha Circle
来源:互联网 发布:mac 搜狗不能使用 编辑:程序博客网 时间:2024/06/07 05:27
problem
题意
- 给出两堆点,问是否存在一个圆,能把其中的一堆全部包含进去但另外一堆全部在圆外面。
思路
这题当时比赛的时候没有人写出来。赛后的题解也迟迟没有给出。给出的题解我只看懂了前半部分。。后半部分应该是比较屌的东西。我的代码还是参考了别人AC的代码写的。思路就是固定两个点,然后对于这一堆点,我们可以求出一个最大半径和一个最小半径,而对于另外的点,我们可以逐个对这个最大和最小半径(其实是圆心到两点中点的距离)进行更新。如果更新到最后,最大半径和最小半径之间仍有范围,那么说明这种情况有解。我能想到枚举所有两个点的组合,但是不知道为什么向代码里这样递归写是正确的。。这题细节颇多,其实就是对方向要有一个很好的认识。。感觉是一道不错的计算几何题目。。
题解翻译
- 看到半夜,终于看懂题解后半部分的意思。真的是太巧妙了,值得去写一个中文版。
- 首先,我们建立一个空间坐标系,也就是在原坐标系上加上z轴
画出一个曲面z=x2+y2 ,然后我们把给定的所有点都投影到这个曲面上。即(x,y,x2+y2) - 然后我们会发现一件事情,即任意一个不垂直于xoy平面的平面,和这个曲面相交得到的曲线,在xoy平面上的投影都是一个圆。
这是可以证明的,联立ax+by+z=1 和x2+y2=z
得到(x+12a)2+(y+12b)2=c+14(a2+b2)
对于xoy平面来说这是一个任意的圆。 所以我们可以得到一个结论,如果原题给定的两个集合中的点在曲面上投影,形成的两个新的集合,可以用一个不垂直于xoy平面的平面分开,那么在xoy平面上,肯定存在这样的一个圆能完成这件事。
给出一张图,是题解里的,更加容易理解这件事情。有了这个结论就好办了。我们对其中的一个集合求凸包,然后求出这些点构成的上凸平面。这可以通过分治的手段来做。求出这些平面之后,我们可以从平面上来判断,另外一个集合是否能和当前集合通过这个面分开(算一下到中垂线的距离)
- 这道题的巧妙之处在于把平面几何通过转换成立体几何,更加直观的证明了一个不太容易想到的结论。个人觉得是一道非常不错的题目。
AC代码
/************************************************************************* > File Name: pe.cpp > Author: znl1087 > Mail: loveCJNforever@gmail.com > Created Time: 日 6/ 7 11:19:33 2015 ************************************************************************/#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <string>#include <cstdlib>#include <vector>#include <set>#include <map>#include <cfloat>using namespace std;const double PI = acos(-1.0);struct Point{ double x,y; Point(double x = 0,double y = 0):x(x),y(y){}};typedef Point Vec;Vec operator + (Vec a,Vec b){return Vec(a.x+b.x,a.y+b.y);}Vec operator - (Point a,Point b){return Vec(a.x-b.x,a.y-b.y);}Vec operator * (Vec a,double p){return Vec(a.x*p,a.y*p);}Vec operator / (Vec a,double p){return a*(1/p);}bool operator < (const Point& a,const Point& b){ return a.x < b.x || (a.x == b.x && a.y < b.y);}const double EPS = 1e-10;int dcmp(double x){ if(fabs(x) < EPS) return 0;else return x < 0 ? -1 : 1;}bool operator == (const Point& a,const Point& b){ return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;}double ang(Vec v){return atan2(v.y,v.x);}double Dot(Vec A,Vec B){return A.x * B.x + A.y * B.y;}double Length(Vec A){return sqrt(Dot(A,A));}double Angle(Vec A,Vec B){return acos(Dot(A,B)/Length(A)/Length(B));}double Cross(Vec A,Vec B){return A.x * B.y - A.y * B.x;}Point CirCenter(Point a,Point b,Point c){ double a1 = b.x - a.x,b1 = b.y - a.y,c1 = (a1 * a1 + b1 * b1)/2; double a2 = c.x - a.x,b2 = c.y - a.y,c2 = (a2 * a2 + b2 * b2)/2; double d = a1 * b2 - a2 * b1; return Point(a.x + (c1 * b2 - c2 * b1)/d,a.y + (a1 * c2 - a2 * c1)/d);}vector<Point> ConvexHull(vector<Point> p){ sort(p.begin(),p.end()); p.erase(unique(p.begin(),p.end()),p.end()); int n = p.size(); vector<Point> ch(n+1); int m = 0; for(int i=0;i<n;i++){ while(m>1 && dcmp(Cross(ch[m-1] - ch[m-2],p[i]-ch[m-2]))<=0)m--; ch[m++] = p[i]; } int k = m; for(int i=n-2;i>=0;i--){ while( m>k && dcmp(Cross(ch[m-1] - ch[m-2],p[i] - ch[m-2])) <= 0)m--; ch[m++] = p[i]; } if( n > 1)m--; ch.resize(m); return ch;}bool judge(const vector<Point>& a,const vector<Point>& b,int i,int j){ double minr =-DBL_MAX,maxr = DBL_MAX; int mid = -1; int na = a.size(),nb = b.size(); bool flag = true; for(int k=i+1;k<j;k++){ if(dcmp(Cross(a[k]-a[i],a[k]-a[j]))==0){ flag = false; break; } Point center = CirCenter(a[i],a[j],a[k]); double r = Length(center - (a[i]+a[j])/2.0); if(dcmp(Cross(center-a[i],a[j]-a[i]))*dcmp(Cross(a[k]-a[i],a[j]-a[i]))<0)r = -r; if(dcmp(r-minr)>0) minr = r,mid = k; } if(flag){ for(int k=(j+1)%na;;k = (k+1)%na){ if(k == i)break; if(dcmp(Cross(a[k]-a[i],a[k]-a[j]))==0){ flag = false; break; } Point center = CirCenter(a[i],a[j],a[k]); double r = Length(center - (a[i]+a[j])/2.0); if(dcmp(Cross(center-a[i],a[j]-a[i]))*dcmp(Cross(a[k]-a[i],a[j]-a[i]))>0)r = -r; if( dcmp(r-maxr)<0)maxr = r; } } //printf("maxr: %lf minr: %lf i: %d j:%d\n",maxr,minr,i,j); bool ok = true; if(flag){ for(int k=0;k<nb;k++){ if(dcmp(Cross(b[k]-a[i],a[j]-a[i]))==0 && dcmp(Dot(a[i]-b[k],a[j]-b[k]))<=0 ){ ok = false; break; } Point center = CirCenter(a[i],a[j],b[k]); double r = Length(center - (a[i]+a[j])/2.0); if(dcmp(Cross(center-a[i],a[j]-a[i]))*dcmp(Cross(b[k]-a[i],a[j]-a[i]))<0)r = -r; //printf("r :%lf x: %lf y:%lf\n",r,b[k].x,b[k].y); if(dcmp(Cross(b[k]-a[i],a[j]-a[i]))>0){ if(dcmp(r-maxr)<0)maxr = r; } else if(dcmp(Cross(b[k]-a[i],a[j]-a[i]))<0){ r = -r; if(dcmp(minr-r)<0)minr = r; } if( dcmp(maxr-minr) <= 0){ ok = false; break; } } } else ok = false; /*if(ok){ printf("%lf %lf\n%lf %lf\n",a[i].x,a[i].y,a[j].x,a[j].y); printf("%lf %lf\n",minr,maxr); }*/ return ok || (mid >=0 && (judge(a,b,i,mid) || judge(a,b,mid,j))); }int n,m;int main(){ scanf("%d%d",&n,&m); vector<Point> ina(n),inb(m); int x,y; for(int i=0;i<n;i++) scanf("%d%d",&x,&y),ina[i].x = (double)x,ina[i].y = (double)y; for(int i=0;i<m;i++) scanf("%d%d",&x,&y),inb[i].x = (double)x,inb[i].y = (double)y; vector<Point> a = ConvexHull(ina),b = ConvexHull(inb); puts((judge(a,inb,0,a.size()-1) || judge(b,ina,0,b.size()-1)) ? "YES" : "NO"); return 0;}
1 0
- Codeforces 549E Sasha Circle
- Codeforces Round #373 (Div. 2) E. Sasha and Array
- Codeforces Round #373 (Div. 2) E. Sasha and Array
- Sasha and Sticks CodeForces
- [Codeforces 719 E. Sasha and Array] 矩阵快速幂+线段树
- CodeForces-719E Sasha and Array(线段树+矩阵快速幂)
- 【Codeforces 718C&719E】Sasha and Array【线段树成段更新+矩阵快速幂】
- 【CodeForces 719E】【线段树+矩阵快速幂】 Sasha and Array
- Codeforces Round #373 (Div. 2) E. Sasha and Array 线段树维护矩阵
- [codeforces] 719E Sasha and Array 线段树+快速斐波那契
- CodeForces 719E Sasha and Array 【线段树】【快速矩阵幂】
- CodeForces - 719E Sasha and Array 线段树 + 矩阵快速幂
- cf/Codeforces Round #373 div1-C/div2-E Sasha and Array 线段树 + 维护矩阵快速幂
- Codeforces 718C C. Sasha and Array
- codeforces 718 C.Sasha and Array
- codeforces 718C - Sasha and Array
- [题解]codeforces 718c Sasha and Array
- Codeforces Round #425 A. Sasha and Sticks
- linux学习之磁盘文件
- 关于反码、补码、原码的一些应用于理解
- 关于 内存对齐 && sizeof 的介绍 1——联合体
- Java程序的运行
- C语言基础:结构体
- Codeforces 549E Sasha Circle
- fsdfsdfsdf
- 单例模式:单例类的标准写法 - iOS - UI基础知识总结13
- 赚大钱才能爱一场。
- C语言基础:函数(Function)
- 大话数据结构—散列表查找(哈希表)
- 关于 内存对齐 && sizeof 的介绍 2 —— 结构体(改)
- linux 的fork 和 vfork
- C语言基础:初级指针