地址:http://poj.org/problem?id=1228

题目:

Grandpa's Estate
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 14326   Accepted: 4004

Description

Being the only living descendant of his grandfather, Kamran the Believer inherited all of the grandpa's belongings. The most valuable one was a piece of convex polygon shaped farm in the grandpa's birth village. The farm was originally separated from the neighboring farms by a thick rope hooked to some spikes (big nails) placed on the boundary of the polygon. But, when Kamran went to visit his farm, he noticed that the rope and some spikes are missing. Your task is to write a program to help Kamran decide whether the boundary of his farm can be exactly determined only by the remaining spikes.

Input

The first line of the input file contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains an integer n (1 <= n <= 1000) which is the number of remaining spikes. Next, there are n lines, one line per spike, each containing a pair of integers which are x and y coordinates of the spike.

Output

There should be one output line per test case containing YES or NO depending on whether the boundary of the farm can be uniquely determined from the input.

Sample Input

1
6
0 0
1 2
3 4
2 0
2 4
5 0

Sample Output

NO

Source

 
思路:
  题意好迷,让你判断凸包是否是稳定凸包。
  稳定凸包:任意一条边上至少有3个点。
  
  我感觉的板子好啰嗦,我要炸了,我要重写板子!!!
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm> using namespace std;
const double PI = acos(-1.0);
const double eps = 1e-;
//点
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 ;
if(ta<tb) return -;
return ;
}
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) == && Point::sgn(y, _off.y) == ;
}
//点位置不同(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();}
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<)
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, ) == ;
}
//点在线段上,参数:点[_Off]
bool shas(const Point &_Off) const
{
return lhas(_Off)
&& Point::sgn(_Off.x - min(s.x, e.x), ) > && Point::sgn(_Off.x - max(s.x, e.x), ) <
&& Point::sgn(_Off.y - min(s.y, e.y), ) > && Point::sgn(_Off.y - max(s.y, e.y), ) < ;
} //点到直线/线段的距离
//参数: 点[_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 - * a * b * _Off.y - * a * c) / d;
ret.y = (a * a * _Off.y - b * b * _Off.y - * a * b * _Off.x - * b * c) / d;
return ret;
}
//计算两点的中垂线
static Line ppline(const Point &_a, const Point &_b)
{
Line ret;
ret.s.x = (_a.x + _b.x) / ;
ret.s.y = (_a.y + _b.y) / ;
//一般式
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, ) == ;
}
//两直线(线段)交点,参数:直线向量[_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 ;
return -;
}
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 ;
}
//------------线段和直线(向量)----------
//线段和直线交
//参数:直线[_st],线段[_se]
friend bool crossSL(const Line &_st,const Line &_se)
{
return Point::sgn((_st / _se.s) * (_st / _se.e) ,) <= ;
} //------------线段和线段(向量)----------
//判断线段是否相交(注意添加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)), ) <= &&
Point::sgn((_se / Line(_se.s, _st.s)) * (_se / Line(_se.s, _st.e)), ) <= ;
}
};
Point ptsort;
bool gcmp(const Point &ta,const Point &tb)/// 选取与最后一条确定边夹角最小的点,即余弦值最大者
{
double tmp=Point::xmult(ptsort,ta,tb);
if(Point::sgn(tmp,)==)
return Point::dis(ptsort,ta)<Point::dis(ptsort,tb);
else if(tmp>)
return ;
return ;
}
class Polygon
{
public:
const static int maxpn = 5e4+;
Point pt[maxpn];//点(顺时针或逆时针)
int n;//点的个数 //求多边形面积,多边形内点必须顺时针或逆时针
double area() const
{
double ans = 0.0;
for(int i = ; i < n; i ++)
{
int nt = (i + ) % 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 = ; i < n; i ++)
{
int nt = (i + ) % 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 /= * area;
ans.y /= * area;
return ans;
}
//判断点在凸多边形内,参数:点[_Off]
bool chas(const Point &_Off) const
{
double tp = , np;
for(int i = ; i < n; i ++)
{
np = Line(pt[i], pt[(i + ) % 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=;
for(int i=;i<_n;i++)
{
while(n>&&Point::sgn(Line(pt[n-],pt[n-])/Line(pt[n-],_p[i]),)<)
n--;
pt[n++]=_p[i];
}
int _key=n;
for(int i=_n-;i>=;i--)
{
while(n>_key&&Point::sgn(Line(pt[n-],pt[n-])/Line(pt[n-],_p[i]),)<)
n--;
pt[n++]=_p[i];
}
if(n>) n--;//除去重复的点,该点已是凸包凸包起点
}
/****** 寻找凸包的graham 扫描法********************/
/****** _p为输入的点集,_n为点的数量****************/
/**使用时需把gmp函数放在Polygon类上面L,ine类下面,并且看情况修改pt[0]**/ void graham(Point _p[],int _n)
{
int cur=;
for(int i=;i<_n;i++)
if(_p[cur].y>_p[i].y || (Point::sgn(_p[cur].y,_p[i].y)== && _p[cur].x>_p[i].x))
cur=i;
swap(_p[cur],_p[]);
n=,pt[n++]=_p[],ptsort=_p[];
if(_n==) return;
sort(_p+,_p+_n,gcmp);
pt[n++]=_p[],pt[n++]=_p[];
for(int i=;i<_n;i++)
{
while(n> && Point::sgn(Point::xmult(pt[n-],pt[n-],_p[i]),)<)// 当凸包退化成直线时需特别注意n
n--;
pt[n++]=_p[i];
}
} }; Point pt[];
Polygon py;
Line ln;
int main(void)
{
int t,n,cs=;cin>>t;
while(t--)
{
int ff=;
scanf("%d",&n);
for(int i=;i<n;i++)
scanf("%lf%lf",&pt[i].x,&pt[i].y);
if(n<) puts("NO");
else
{
py.graham(pt,n);
py.pt[py.n]=py.pt[];
// for(int i=0;i<py.n;i++)
// printf("==%.2f %.2f\n",py.pt[i].x,py.pt[i].y);
for(int i=;i<py.n-&&ff;i++)
if(Point::xmult(py.pt[i-],py.pt[i+],py.pt[i])!=&&Point::xmult(py.pt[i],py.pt[i+],py.pt[i+])!=)
ff=;
if(ff)
puts("YES");
else
puts("NO");
} }
return ;
}

poj1228 Grandpa's Estate的更多相关文章

  1. POJ1228 Grandpa's Estate 稳定凸包

    POJ1228 转自http://www.cnblogs.com/xdruid/archive/2012/06/20/2555536.html   这道题算是很好的一道凸包的题吧,做完后会加深对凸包的 ...

  2. POJ 1228 Grandpa's Estate(凸包)

    Grandpa's Estate Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11289   Accepted: 3117 ...

  3. POJ1228:Grandpa's Estate(给定一些点,问是否可以确定一个凸包)

    Being the only living descendant of his grandfather, Kamran the Believer inherited all of the grandp ...

  4. POJ1228:Grandpa's Estate——题解

    http://poj.org/problem?id=1228 题目大意:给一个凸包,问是否为稳定凸包. ———————————————————————— 稳定凸包的概念为:我任意添加一个点都不能使这个 ...

  5. 【POJ】1228 Grandpa's Estate(凸包)

    http://poj.org/problem?id=1228 随便看看就能发现,凸包上的每条边必须满足,有相邻的边和它斜率相同(即共线或凸包上每个点必须一定在三点共线上) 然后愉快敲完凸包+斜率判定, ...

  6. POJ 1228 Grandpa's Estate(凸包唯一性判断)

    Description Being the only living descendant of his grandfather, Kamran the Believer inherited all o ...

  7. POJ 1228 Grandpa's Estate --深入理解凸包

    题意: 判断凸包是否稳定. 解法: 稳定凸包每条边上至少有三个点. 这题就在于求凸包的细节了,求凸包有两种算法: 1.基于水平序的Andrew算法 2.基于极角序的Graham算法 两种算法都有一个类 ...

  8. 【POJ 1228】Grandpa's Estate 凸包

    找到凸包后暴力枚举边进行$check$,注意凸包是一条线(或者说两条线)的情况要输出$NO$ #include<cmath> #include<cstdio> #include ...

  9. POJ 1228 - Grandpa's Estate 稳定凸包

    稳定凸包问题 要求每条边上至少有三个点,且对凸包上点数为1,2时要特判 巨坑无比,调了很长时间= = //POJ 1228 //稳定凸包问题,等价于每条边上至少有三个点,但对m = 1(点)和m = ...

随机推荐

  1. android studio如何生成签名文件,以及SHA1和MD5值

    一.生成签名文件 1.点击菜单栏中的Build的. 2.弹出窗体,如下图,选中Generate Signed APK,并点击. 3.弹出窗体,如下图. 4.点击Create new…按钮,创建一个签名 ...

  2. 在centos命令行下安装软件

    考虑到用linux纯命令行模式时,通常都是用作服务器,所以,一般主要是安装一个php.mysql.apache的集成环境和ftp服务器,在这里用xampp集成包即可解决所有问题,在这里说一下我自己的做 ...

  3. poj_3579 二分法

    题目大意 给定N个数,这些数字两两求差构成C(N,2)(即N*(N-1)/2)个数值,求这C(N,2)个数的中位数.N <= 100000. 题目分析 根据数据规模N最大为100000,可知不能 ...

  4. scss的安装使用

    Ruby的安装 如果是Window系统,请打开:http://rubyinstaller.org/downloads/ ,下载当前稳定版本的exe文件.界面如下所示: Step(2): 接下来,在系统 ...

  5. 【BZOJ3939】[Usaco2015 Feb]Cow Hopscotch 动态规划+线段树

    [BZOJ3939][Usaco2015 Feb]Cow Hopscotch Description Just like humans enjoy playing the game of Hopsco ...

  6. ios unrecognized selector sent to instance出现的原因和解决方案

    概述:造成unrecognized selector sent to instance iphone,大部分情况下是因为对象被提前release了,在你心里不希望他release的情况下,指针还在,对 ...

  7. 【Android】ImageMap,图片地图

    https://github.com/CFutureTeam/android-image-map package com.*.imagemap; import *.imagemap.ImageMap; ...

  8. Iterator 和 Iterable 区别和联系

    首先预览下Java源码中的Iterator和Iterable: Iterable接口: public interface Iterable<T> {//这里只摘录接口中的抽象方法 /** ...

  9. Python 自学积累(二)

    1. onfigParser 模块用于操作配置文件 注:Parser汉译为“解析”之意. 配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数( ...

  10. 170526、spring 执行定时任务

    Spring 定时任务之 @Scheduled cron表达式 一.使用 Spring配置文件xmlns加入 xmlns:task="http://www.springframework.o ...