POJ 1228 Grandpa's Estate (凸包、保留凸包边上的点)
2016-09-03 09:34
453 查看
题目链接:http://poj.org/problem?id=1228
题意:输入一个凸包上的点(没有凸包内部的点,要么是凸包顶点,要么是凸包边上的点),判断这个凸包是否稳定。所谓稳定就是判断能不能在原有凸包上加点,得到一个更大的凸包,并且这个凸包包含原有凸包上的所有点。
参考博客:http://blog.csdn.net/acdreamers/article/details/10023615
当一个凸包稳定时,凸包的每条边上都要有至少3个点,若只有两个点,则一定可以增加一个点,得到更大的凸包。这样我们可以求出凸包,在求凸包时把共线的点也加进来,这样我们就判断是否有连续的三点共线即可,具体参见代码。
搞了半天也没想明白怎样用Graham算法来保存所有凸包边上共线的点。不过网上竟然有人这样过了.....
一晚上没搞出来,第二天换了种比较蠢的办法,就是先求出凸包顶点,然后对每条边枚举所有点看是否每条边全都是有三个以上的点。这样也可以过,不过还要特判所有点共线的情况,这种情况下凸包Stack里面就只有2个点了,很容易判断。 下面是代码:
附带上一个第二天下午写的,通过Andrew算法保留边上点的做法。网上很多代码,道理讲得很明白,可代码明显有错,有的连所有点共线的情况都没考虑,虽然能过.....
再研究一下怎样求凸包时保存所有边上的顶点....
Andrew算法:
题意:输入一个凸包上的点(没有凸包内部的点,要么是凸包顶点,要么是凸包边上的点),判断这个凸包是否稳定。所谓稳定就是判断能不能在原有凸包上加点,得到一个更大的凸包,并且这个凸包包含原有凸包上的所有点。
参考博客:http://blog.csdn.net/acdreamers/article/details/10023615
当一个凸包稳定时,凸包的每条边上都要有至少3个点,若只有两个点,则一定可以增加一个点,得到更大的凸包。这样我们可以求出凸包,在求凸包时把共线的点也加进来,这样我们就判断是否有连续的三点共线即可,具体参见代码。
搞了半天也没想明白怎样用Graham算法来保存所有凸包边上共线的点。不过网上竟然有人这样过了.....
一晚上没搞出来,第二天换了种比较蠢的办法,就是先求出凸包顶点,然后对每条边枚举所有点看是否每条边全都是有三个以上的点。这样也可以过,不过还要特判所有点共线的情况,这种情况下凸包Stack里面就只有2个点了,很容易判断。 下面是代码:
附带上一个第二天下午写的,通过Andrew算法保留边上点的做法。网上很多代码,道理讲得很明白,可代码明显有错,有的连所有点共线的情况都没考虑,虽然能过.....
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <cmath> using namespace std; const double eps = 1e-8; const double PI = acos(-1.0); int sgn(double x) { if(fabs(x) < eps)return 0; if(x < 0)return -1; else return 1; } struct Point { double x,y, v, l; Point(){} Point(double _x,double _y) { x = _x;y = _y; } Point operator -(const Point &b)const { return Point(x - b.x,y - b.y); } double operator ^(const Point &b)const { return x*b.y - y*b.x; } double operator *(const Point &b)const { return x*b.x + y*b.y; } void transXY(double B) { double tx = x,ty = y; x = tx*cos(B) - ty*sin(B); y = tx*sin(B) + ty*cos(B); } }; struct Line { Point s,e; Line(){} Line(Point _s,Point _e) { s = _s;e = _e; } pair<int,Point> operator &(const Line &b)const { Point res = s; if(sgn((s-e)^(b.s-b.e)) == 0) { if(sgn((s-b.e)^(b.s-b.e)) == 0) return make_pair(0,res); else return make_pair(1,res); } double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e)); res.x += (e.x-s.x)*t; res.y += (e.y-s.y)*t; return make_pair(2,res); } }; double dist(Point a,Point b) { return sqrt((a-b)*(a-b)); } const int MAXN = 1010; Point list[MAXN]; int Stack[MAXN], top; bool _cmp(Point p1,Point p2) { double tmp = (p1-list[0])^(p2-list[0]); if(sgn(tmp) > 0)return true; else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0) return true; else return false; } void Graham(int n) { Point p0; int k = 0; p0 = list[0]; for(int i = 1;i < n;i++) { if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) ) { p0 = list[i]; k = i; } } swap(list[k],list[0]); sort(list+1,list+n,_cmp); if(n == 1) { top = 1; Stack[0] = 0; return; } if(n == 2) { top = 2; Stack[0] = 0; Stack[1] = 1; return ; } Stack[0] = 0; Stack[1] = 1; top = 2; for(int i = 2;i < n;i++) { while(top > 1 && sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 0){ top--; } Stack[top++] = i; } } int main() { int t; scanf("%d", &t); while(t--) { int n; scanf("%d", &n); int i, j; for(i = 0; i < n; i++) { scanf("%lf %lf", &list[i].x, &list[i].y); } if(n < 6) { //特判 puts("NO"); continue; } Graham(n); if(top <= 2) { //所有点共线 puts("NO"); continue; } int flag = 1; for(i = 0; i < top; i++) { Line l1(list[Stack[i]], list[Stack[(i + 1) % top]]); for(j = 0; j < n; j++) { if(j == Stack[i] || j == Stack[(i + 1) % top]) continue; Line l2(list[Stack[i]], list[j]); pair<int ,Point> p = (l1 & l2); if(p.first == 0) { break; } } if(j == n) { //有一条边无共线点 flag = 0; break; } } puts(flag ? "YES" : "NO"); } return 0; }
再研究一下怎样求凸包时保存所有边上的顶点....
Andrew算法:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <cmath> using namespace std; const double eps = 1e-8; const double PI = acos(-1.0); int sgn(double x) { if(fabs(x) < eps)return 0; if(x < 0)return -1; else return 1; } struct Point { double x,y, v, l; Point(){} Point(double _x,double _y) { x = _x;y = _y; } Point operator -(const Point &b)const { return Point(x - b.x,y - b.y); } double operator ^(const Point &b)const { return x*b.y - y*b.x; } double operator *(const Point &b)const { return x*b.x + y*b.y; } void transXY(double B) { double tx = x,ty = y; x = tx*cos(B) - ty*sin(B); y = tx*sin(B) + ty*cos(B); } }; struct Line { Point s,e; Line(){} Line(Point _s,Point _e) { s = _s;e = _e; } pair<int,Point> operator &(const Line &b)const { Point res = s; if(sgn((s-e)^(b.s-b.e)) == 0) { if(sgn((s-b.e)^(b.s-b.e)) == 0) return make_pair(0,res); else return make_pair(1,res); } double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e)); res.x += (e.x-s.x)*t; res.y += (e.y-s.y)*t; return make_pair(2,res); } }; double dist(Point a,Point b) { return sqrt((a-b)*(a-b)); } ///计算凸包,输入点数组p,个数为n,输出点数组ch。函数返回凸包顶点数。 ///输入不能有重复点,函数执行完成之后输入点的顺序被破坏。 ///如果不希望凸包的边上有输入点,把两个 < 改成 <= ///在精度要求高时,应该使用dcmp函数比较 const int MAXN = 1010; Point list[MAXN]; Point Stack[MAXN]; int top; bool _cmp(Point p1,Point p2) { if(p1.x != p2.x) return p1.x < p2.x; else return p1.y < p2.y; } int Andrew(Point *p, int n, Point *ch) { //不加=号,逆时针顺序保存所有点 sort(p, p + n, _cmp); int m = 0; for(int i = 0; i < n; i++) { while(m > 1 && ((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 && ((ch[m - 1] - ch[m - 2]) ^ (p[i] - ch[m - 2])) < 0) m--; ch[m++] = p[i]; } if(n > 1) m--; return m; } int main() { int t; scanf("%d", &t); while(t--) { int n; scanf("%d", &n); int i, j; for(i = 0; i < n; i++) { scanf("%lf %lf", &list[i].x, &list[i].y); } if(n < 6) { //特判 puts("NO"); continue; } top = Andrew(list, n, Stack); for(i = 0; i < top - 2; i++) { //判断是否所有点都共线 Line l1(Stack[i], Stack[i + 1]); Line l2(Stack[i + 1], Stack[i + 2]); if((l1 & l2).first != 0) { break; } } if(i == top - 2) { puts("NO"); continue; } int flag = 1; for(i = 0; i < top; i++) { //每两个点为一组,判断是否每条边上至少三个点 Line l1(Stack[((i - 1) + top) % top], Stack[i]); Line l2(Stack[((i - 1) + top) % top], Stack[(i + 1) % top]); Line l3(Stack[i], Stack[(i + 1) % top]); Line l4(Stack[i], Stack[(i + 2) % top]); pair<int, Point> p1 = (l1 & l2); pair<int, Point> p2 = (l3 & l4); if(p1.first != 0 && p2.first != 0) { flag = 0; break; } } puts(flag ? "YES" : "NO"); } return 0; }
相关文章推荐
- poj 1228 Grandpa's Estate(凸包+判凸包边上的点数)
- POJ 1228 Grandpa's Estate (凸包唯一性判定 推荐)
- poj 1228 Grandpa's Estate[稳定凸包]
- poj 1228 Grandpa's Estate(凸包)
- POJ 1228 Grandpa's Estate (求稳定凸包)
- POJ 1228 Grandpa's Estate(给定凸包上的一部分顶点 判断表示的凸包是否唯一)
- POJ 1228:Grandpa's Estate (稳定凸包)
- POJ 1228 Grandpa's Estate(凸包应用:稳定凸包)
- POJ 1228 Grandpa's Estate 【计算几何:凸包,andrew】
- poj 1228 Grandpa's Estate(凸包边上的点数)
- Grandpa's Estate - POJ 1228(稳定凸包)
- POJ 1228 Grandpa's Estate(凸包应用:稳定凸包)
- POJ 1228 Grandpa's Estate(凸包)
- POJ 1228 Grandpa's Estate(判断是否稳定凸包)
- poj-1228 Grandpa's Estate(判断凸包是否唯一)
- POJ 1228 Grandpa's Estate (凸包)
- POJ 1228 Grandpa's Estate【稳定凸包判断】
- 【凸包性质】 POJ 1228 Grandpa's Estate
- poj 1228 Grandpa's Estate 凸包模板题
- POJ1228-Grandpa's Estate(凸包)