地址: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. Windows7安装Mongodb

    1.安装mongodb-win32-x86_64-3.0.4-signed.msi 2.安装kb2731284 安装补丁:Windows6.1-KB2731284-v3-x64.msu 3.创建数据库 ...

  2. UIGestureRecognizer学习笔记

    一.Gesture Recognizers Gesture Recognizers是在iOS3.2引入的,可以用来识别手势.简化定制视图事件处理的对象.Gesture Recognizers的基类为U ...

  3. 集群应用Session一致性实现的三种方案

    转自:http://blog.csdn.net/zwx521515/article/details/78679679 https://www.cnblogs.com/study-everyday/p/ ...

  4. call和apply方法

    /* * @ call和apply方法 * @ 当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作. * @ (有方法的)对象.call(" ...

  5. sql语句查询条件的不同表达方式对查询性能的影响

    今天操作数据库遇到一个问题 目标表RA_AD_DAILY_DATA的数据量大概有5千万左右,其中的BUSINESS_DATE字段为日期类型 我要查询8月20号导入的三条记录,刚开始用这种方式去查: S ...

  6. 【BZOJ2599】[IOI2011]Race 树的点分治

    [BZOJ2599][IOI2011]Race Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 100000 ...

  7. [XML] CoolFormat

    http://files.cnblogs.com/files/wjs16/CoolFormat3.4.rar

  8. android通过数组,流播放声音的方法,音频实时传输

    AudioRecord和AudioTrack类是Android获取和播放音频流的重要类,放置在android.media包中.与该包中 的MediaRecorder和MediaPlayer类不同,Au ...

  9. JSTL的一些使用规范,坑

    三目表达式要加空格不然有些服务器解析不了 var maxBanners = ${maxBanners==null ? 3 : maxBanners}; forEach循环的长度正确使用方式 <c ...

  10. windows本地环境如何用wamp配置多域名绑定访问

    https://jingyan.baidu.com/article/acf728fd5fcdadf8e510a3e5.html