标签:amr col shape visit rom out swap move 输入
地址:http://poj.org/problem?id=1228
题目:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 14326 | Accepted: 4004 |
Description
Input
Output
Sample Input
1 6 0 0 1 2 3 4 2 0 2 4 5 0
Sample Output
NO
Source
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; const double PI = acos(-1.0); const double eps = 1e-10; //点 class Point { public: double x, y; Point(){} Point(double x, double y):x(x),y(y){} bool operator < (const Point &_se) const { return x<_se.x || (x==_se.x && y<_se.y); } /*******判断ta与tb的大小关系*******/ static int sgn(double ta,double tb) { if(fabs(ta-tb)<eps)return 0; if(ta<tb) return -1; return 1; } static double xmult(const Point &po, const Point &ps, const Point &pe) { return (ps.x - po.x) * (pe.y - po.y) - (pe.x - po.x) * (ps.y - po.y); } friend Point operator + (const Point &_st,const Point &_se) { return Point(_st.x + _se.x, _st.y + _se.y); } friend Point operator - (const Point &_st,const Point &_se) { return Point(_st.x - _se.x, _st.y - _se.y); } //点位置相同(double类型) bool operator == (const Point &_off) const { return Point::sgn(x, _off.x) == 0 && Point::sgn(y, _off.y) == 0; } //点位置不同(double类型) bool operator != (const Point &_Off) const { return ((*this) == _Off) == false; } //两点间距离的平方 static double dis2(const Point &_st,const Point &_se) { return (_st.x - _se.x) * (_st.x - _se.x) + (_st.y - _se.y) * (_st.y - _se.y); } //两点间距离 static double dis(const Point &_st, const Point &_se) { return sqrt((_st.x - _se.x) * (_st.x - _se.x) + (_st.y - _se.y) * (_st.y - _se.y)); } }; //两点表示的向量 class Line { public: Point s, e;//两点表示,起点[s],终点[e] double a, b, c;//一般式,ax+by+c=0 double angle;//向量的角度,[-pi,pi] Line(){} Line(const Point &s, const Point &e):s(s),e(e){get_angle(1);} Line(double _a,double _b,double _c):a(_a),b(_b),c(_c){} //向量与点的叉乘,参数:点[_Off] //[点相对向量位置判断] double operator /(const Point &_Off) const { return (_Off.y - s.y) * (e.x - s.x) - (_Off.x - s.x) * (e.y - s.y); } //向量与向量的叉乘,参数:向量[_Off] friend double operator /(const Line &_st,const Line &_se) { return (_st.e.x - _st.s.x) * (_se.e.y - _se.s.y) - (_st.e.y - _st.s.y) * (_se.e.x - _se.s.x); } friend double operator *(const Line &_st,const Line &_se) { return (_st.e.x - _st.s.x) * (_se.e.x - _se.s.x) - (_st.e.y - _st.s.y) * (_se.e.y - _se.s.y); } //从两点表示转换为一般表示 //a=y2-y1,b=x1-x2,c=x2*y1-x1*y2 bool pton() { a = e.y - s.y; b = s.x - e.x; c = e.x * s.y - e.y * s.x; return true; } //求直线或向量的角度 double get_angle(bool isVector) { angle=atan2(e.y-s.y,e.x-s.x); if(!isVector && angle<0) angle+=PI; return angle; } // bool operator < (const Line &ta)const { return angle<ta.angle; } //-----------点和直线(向量)----------- //点在向量左边(右边的小于号改成大于号即可,在对应直线上则加上=号) //参数:点[_Off],向量[_Ori] friend bool operator<(const Point &_Off, const Line &_Ori) { return (_Ori.e.y - _Ori.s.y) * (_Off.x - _Ori.s.x) < (_Off.y - _Ori.s.y) * (_Ori.e.x - _Ori.s.x); } //点在直线上,参数:点[_Off] bool lhas(const Point &_Off) const { return Point::sgn((*this) / _Off, 0) == 0; } //点在线段上,参数:点[_Off] bool shas(const Point &_Off) const { return lhas(_Off) && Point::sgn(_Off.x - min(s.x, e.x), 0) > 0 && Point::sgn(_Off.x - max(s.x, e.x), 0) < 0 && Point::sgn(_Off.y - min(s.y, e.y), 0) > 0 && Point::sgn(_Off.y - max(s.y, e.y), 0) < 0; } //点到直线/线段的距离 //参数: 点[_Off], 是否是线段[isSegment](默认为直线) double dis(const Point &_Off, bool isSegment = false) { ///化为一般式 pton(); //到直线垂足的距离 double td = (a * _Off.x + b * _Off.y + c) / sqrt(a * a + b * b); //如果是线段判断垂足 if(isSegment) { double xp = (b * b * _Off.x - a * b * _Off.y - a * c) / ( a * a + b * b); double yp = (-a * b * _Off.x + a * a * _Off.y - b * c) / (a * a + b * b); double xb = max(s.x, e.x); double yb = max(s.y, e.y); double xs = s.x + e.x - xb; double ys = s.y + e.y - yb; if(xp > xb + eps || xp < xs - eps || yp > yb + eps || yp < ys - eps) td = min(Point::dis(_Off,s), Point::dis(_Off,e)); } return fabs(td); } //关于直线对称的点 Point mirror(const Point &_Off) const { ///注意先转为一般式 Point ret; double d = a * a + b * b; ret.x = (b * b * _Off.x - a * a * _Off.x - 2 * a * b * _Off.y - 2 * a * c) / d; ret.y = (a * a * _Off.y - b * b * _Off.y - 2 * a * b * _Off.x - 2 * b * c) / d; return ret; } //计算两点的中垂线 static Line ppline(const Point &_a, const Point &_b) { Line ret; ret.s.x = (_a.x + _b.x) / 2; ret.s.y = (_a.y + _b.y) / 2; //一般式 ret.a = _b.x - _a.x; ret.b = _b.y - _a.y; ret.c = (_a.y - _b.y) * ret.s.y + (_a.x - _b.x) * ret.s.x; //两点式 if(std::fabs(ret.a) > eps) { ret.e.y = 0.0; ret.e.x = - ret.c / ret.a; if(ret.e == ret. s) { ret.e.y = 1e10; ret.e.x = - (ret.c - ret.b * ret.e.y) / ret.a; } } else { ret.e.x = 0.0; ret.e.y = - ret.c / ret.b; if(ret.e == ret. s) { ret.e.x = 1e10; ret.e.y = - (ret.c - ret.a * ret.e.x) / ret.b; } } return ret; } //------------直线和直线(向量)------------- //直线向左边平移t的距离 Line& moveLine(double t) { Point of; of=Point(-(e.y-s.y),e.x-s.x); double dis=sqrt(of.x*of.x+of.y*of.y); of.x=of.x*t/dis,of.y=of.y*t/dis; s=s+of,e=e+of; return *this; } //直线重合,参数:直线向量[_st],[_se] static bool equal(const Line &_st, const Line &_se) { return _st.lhas(_se.e) && _se.lhas(_se.s); } //直线平行,参数:直线向量[_st],[_se] static bool parallel(const Line &_st,const Line &_se) { return Point::sgn(_st / _se, 0) == 0; } //两直线(线段)交点,参数:直线向量[_st],[_se],交点 //返回-1代表平行,0代表重合,1代表相交 static bool crossLPt(const Line &_st,const Line &_se,Point &ret) { if(Line::parallel(_st,_se)) { if(Line::equal(_st,_se)) return 0; return -1; } ret = _st.s; double t = (Line(_st.s,_se.s)/_se)/(_st/_se); ret.x += (_st.e.x - _st.s.x) * t; ret.y += (_st.e.y - _st.s.y) * t; return 1; } //------------线段和直线(向量)---------- //线段和直线交 //参数:直线[_st],线段[_se] friend bool crossSL(const Line &_st,const Line &_se) { return Point::sgn((_st / _se.s) * (_st / _se.e) ,0) <= 0; } //------------线段和线段(向量)---------- //判断线段是否相交(注意添加eps),参数:线段[_st],线段[_se] static bool isCrossSS(const Line &_st,const Line &_se) { //1.快速排斥试验判断以两条线段为对角线的两个矩形是否相交 //2.跨立试验(等于0时端点重合) return max(_st.s.x, _st.e.x) >= min(_se.s.x, _se.e.x) && max(_se.s.x, _se.e.x) >= min(_st.s.x, _st.e.x) && max(_st.s.y, _st.e.y) >= min(_se.s.y, _se.e.y) && max(_se.s.y, _se.e.y) >= min(_st.s.y, _st.e.y) && Point::sgn((_st / Line(_st.s, _se.s)) * (_st / Line(_st.s, _se.e)), 0) <= 0 && Point::sgn((_se / Line(_se.s, _st.s)) * (_se / Line(_se.s, _st.e)), 0) <= 0; } }; Point ptsort; bool gcmp(const Point &ta,const Point &tb)/// 选取与最后一条确定边夹角最小的点,即余弦值最大者 { double tmp=Point::xmult(ptsort,ta,tb); if(Point::sgn(tmp,0)==0) return Point::dis(ptsort,ta)<Point::dis(ptsort,tb); else if(tmp>0) return 1; return 0; } class Polygon { public: const static int maxpn = 5e4+7; Point pt[maxpn];//点(顺时针或逆时针) int n;//点的个数 //求多边形面积,多边形内点必须顺时针或逆时针 double area() const { double ans = 0.0; for(int i = 0; i < n; i ++) { int nt = (i + 1) % n; ans += pt[i].x * pt[nt].y - pt[nt].x * pt[i].y; } return fabs(ans / 2.0); } //求多边形重心,多边形内点必须顺时针或逆时针 Point gravity() const { Point ans; ans.x = ans.y = 0.0; double area = 0.0; for(int i = 0; i < n; i ++) { int nt = (i + 1) % n; double tp = pt[i].x * pt[nt].y - pt[nt].x * pt[i].y; area += tp; ans.x += tp * (pt[i].x + pt[nt].x); ans.y += tp * (pt[i].y + pt[nt].y); } ans.x /= 3 * area; ans.y /= 3 * area; return ans; } //判断点在凸多边形内,参数:点[_Off] bool chas(const Point &_Off) const { double tp = 0, np; for(int i = 0; i < n; i ++) { np = Line(pt[i], pt[(i + 1) % n]) / _Off; if(tp * np < -eps) return false; tp = (fabs(np) > eps)?np: tp; } return true; } /** 卷包裹法求点集凸包,_p为输入点集,_n为点的数量 **/ void ConvexClosure(Point _p[],int _n) { sort(_p,_p+_n); n=0; for(int i=0;i<_n;i++) { while(n>1&&Point::sgn(Line(pt[n-2],pt[n-1])/Line(pt[n-2],_p[i]),0)<0) n--; pt[n++]=_p[i]; } int _key=n; for(int i=_n-2;i>=0;i--) { while(n>_key&&Point::sgn(Line(pt[n-2],pt[n-1])/Line(pt[n-2],_p[i]),0)<0) n--; pt[n++]=_p[i]; } if(n>1) n--;//除去重复的点,该点已是凸包凸包起点 } /****** 寻找凸包的graham 扫描法********************/ /****** _p为输入的点集,_n为点的数量****************/ /**使用时需把gmp函数放在Polygon类上面L,ine类下面,并且看情况修改pt[0]**/ void graham(Point _p[],int _n) { int cur=0; for(int i=1;i<_n;i++) if(_p[cur].y>_p[i].y || (Point::sgn(_p[cur].y,_p[i].y)==0 && _p[cur].x>_p[i].x)) cur=i; swap(_p[cur],_p[0]); n=0,pt[n++]=_p[0],ptsort=_p[0]; if(_n==1) return; sort(_p+1,_p+_n,gcmp); pt[n++]=_p[1],pt[n++]=_p[2]; for(int i=3;i<_n;i++) { while(n>1 && Point::sgn(Point::xmult(pt[n-2],pt[n-1],_p[i]),0)<0)// 当凸包退化成直线时需特别注意n n--; pt[n++]=_p[i]; } } }; Point pt[1200]; Polygon py; Line ln; int main(void) { int t,n,cs=1;cin>>t; while(t--) { int ff=1; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%lf%lf",&pt[i].x,&pt[i].y); if(n<6) puts("NO"); else { py.graham(pt,n); py.pt[py.n]=py.pt[0]; // for(int i=0;i<py.n;i++) // printf("==%.2f %.2f\n",py.pt[i].x,py.pt[i].y); for(int i=1;i<py.n-1&&ff;i++) if(Point::xmult(py.pt[i-1],py.pt[i+1],py.pt[i])!=0&&Point::xmult(py.pt[i],py.pt[i+2],py.pt[i+1])!=0) ff=0; if(ff) puts("YES"); else puts("NO"); } } return 0; }
标签:amr col shape visit rom out swap move 输入
原文地址:http://www.cnblogs.com/weeping/p/7625794.html