地址: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. 处理unsigned相减错误(BIGINT UNSIGNED value is out of range)

    mysql 当两个字段想减时,如果其中一个或两个字段的类型的unsigned无签名类型,如果想减的值小于0则会报错(BIGINT UNSIGNED value is out of range) 测试: ...

  2. sqlmap tutorial

    svn checkout https://svn.sqlmap.org/sqlmap/trunk/sqlmap sqlmap-dev sqlmap.py -u "http://www.isl ...

  3. 开源项目源码解析-PhotoView 源码解析

    1. 功能介绍 特性(Features): 支持 Pinch 手势自由缩放. 支持双击放大/还原. 支持平滑滚动. 在滑动父控件下能够运行良好.(例如:ViewPager) 支持基于 Matrix 变 ...

  4. 用Broadcast Receiver刷新数据(二)

    采用消息发布/订阅的一个很大的优点就是代码的简洁性,并且能够有效地降低消息发布者和订阅者之间的耦合度.举个例子,比如有两个界面,ActivityA和ActivityB,从ActivityA界面跳转到A ...

  5. jQuery中的$.each的用法

    $.each(Array,function(i,value){ this;  //this指向当前对象 i;       //i表示当前下标 value; //value表示当前元素 })

  6. Java中UDP协议的基本原理和简单用法

    UDP协议是非面向连接的,相对于TCP协议效率较高,但是不安全.UDP协议类似发信息的过程,不管接收方是在线还是关机状态,都会把信息发送出去.但是如果接收方不处于接收信息的状态,发送出去的数据包就会丢 ...

  7. flask框架实战项目架构

    一.项目架构: 研习了多天flask,今天终于按照标准流程写了一个实验demo,并实现了ORM调用,一起喜欢自己写原生SQL.废话不多说,来看项目文件结构 mysite/ ./config/ defa ...

  8. EUI组件之CheckBox

    一.CheckBox常规使用 拖动一个checkBox到exml即可 点击效果 二.代码中监听事件 /** * 主页场景 * @author chenkai 2018/5/26 */ class Ho ...

  9. 【BZOJ1529】[POI2005]ska Piggy banks Tarjan

    [BZOJ1529][POI2005]ska Piggy banks Description Byteazar 有 N 个小猪存钱罐. 每个存钱罐只能用钥匙打开或者砸开. Byteazar 已经把每个 ...

  10. angular -- 无刷新做分页

    无刷新做分页参考地址: http://www.jq22.com/demo/angular201707111100/ 示例代码: <!DOCTYPE html> <html lang= ...