POJ 1228 Grandpa's Estate 计算凸包+判断点在线段上
来源:互联网 发布:医院网络通知管理 编辑:程序博客网 时间:2024/04/28 21:30
题目链接:http://poj.org/problem?id=1228
题目大意:给定n个二维坐标系中的点,这些点是一个凸多边形顶点的子集。判断这些点是否能唯一确定原来的凸多边形。
解题思路:
考虑多边形的一条边。对于给定两个端点,连起来变成一条边。原来的多边形中可能在这条边之外还有一个端点p',那么这条边在原多边形中可能就不存在。 那么怎么能确定一条边一定在原多边形中存在呢?
如果在一条线段上除了端点p1 p2之外有其他的点p3,那么这条边在原多边形中一定存在。因为不可能添加一个顶点使得这条线段仍然是凸的。p3限制了线段p1p2向外凸出。所以只需要先对点集求个凸包,然后判断凸包的每条边上是否都有除了端点之外的第三个点,使得这条边确定下来。如果凸包中的每条边都满足这个条件,便可唯一确定原来的凸多边形。
另外这道题也有需要特判的情况,以上的分析都基于能求出一个多边形凸包,实际上这样的凸包可能并不存在。我使用的是xy坐标排序的graham-scan算法,如果所有的点都共线的话,算法依然会求出一个点集(包括了输入的所有的点),并且可能判断出点集中每条的线段上都有第三个顶点,然后输出YES。实际上很显然,直线外可能存在其他的顶点把这条线“撑开”,答案应该是NO。所以必须特判所有顶点共线的情况。按照惯例,考虑n的极限情况,n=1时,只有一个顶点。这时候判断共线的函数会把这种情况判断成共线,所以n=1时也没有问题。
至于复杂度: 求凸包O(nlogn),判断唯一性时枚举每条边和每个点,O(nh),其中h是凸包中点的数目。所以总复杂度在O(nlogn)和O(nh)之间。
/* * 2014.11.8 * Problem: 1228 * Memory: 204K * Time: 16MS */#include "stdio.h"#include "math.h"#define EPS 1e-8#define MAXN 2007struct Point {double x, y;}p[MAXN], c[MAXN];int n, top;void sort(int l, int r) {int i=l, j=r;double x = p[(l+r)>>1].x, y = p[(l+r)>>1].y;do {while (p[i].x<x || (p[i].x==x && p[i].y<y)) i++;while (p[j].x>x || (p[j].x==x && p[j].y>y)) j--;if (i<=j) {Point t = p[i]; p[i] = p[j]; p[j] = t;i++; j--;}} while (i<=j);if (i<r) sort(i, r);if (l<j) sort(l, j);}double max(double a, double b) {return a>b?a:b;}double min(double a, double b) {return a>b?b:a;}// 叉积double cross(Point a, Point b, Point c) {double x1 = b.x-a.x, y1 = b.y-a.y;double x2 = c.x-a.x, y2 = c.y-a.y;return x1*y2-x2*y1;}// 判断是否左转, 包括共线情况bool turnLeft(Point a, Point b, Point c) {return cross(a, b, c)>=-EPS;}// 求凸包void convexHull() {sort(1, n);top = 1; c[top] = p[1];for (int i=2;i<=n;i++) {while (top>=2 && turnLeft(c[top-1], c[top], p[i])) top--;c[++top] = p[i];}int pn = top;for (int i=n-1;i>=1;i--) {while (top>=pn+1 && turnLeft(c[top-1], c[top], p[i])) top--;c[++top] = p[i];}top --;}// 判断点是否在线段上,不包括端点bool onSegment(Point a, Point b, Point c) {if (fabs(cross(a, b, c))<EPS && min(a.x,b.x)<=c.x && c.x<=max(a.x,b.x) && min(a.y,b.y)<=c.y && c.y<=max(a.y,b.y) &&!((c.x==a.x&&c.y==a.y)||(c.x==b.x&&c.y==b.y))) return true;return false;}// 验证凸包中的每一条边是否确定bool verify() {c[top+1] = c[1];for (int i=1;i<=top;i++) {bool on = false;for (int j=1;j<=n;j++)if (onSegment(c[i], c[i+1], p[j])) {on = true;break;}if (!on) return false; }return true;}// 判断所有点是否共线bool collinear() {p[n+1] = p[1];p[n+2] = p[2];for (int i=1;i<=n;i++) if (fabs(cross(p[i],p[i+1],p[i+2]))>EPS) return false;return true;}int main() {int t;scanf("%d", &t);while (t--) {scanf("%d", &n);for (int i=1;i<=n;i++) scanf("%lf %lf", &p[i].x, &p[i].y);// 判断顶点是否共线,如果共线直接输出NOif (collinear()) {printf("NO\n");continue;}// 求凸包, 凸包上的点保存在 c 数组中convexHull();// 判断凸包上的点是否能唯一确定一个凸多边形// 即判断凸包每条线段上都有除了端点外的点bool only = verify();if (only) {printf("YES\n");} else {printf("NO\n");}}return 0;}
0 0
- POJ 1228 Grandpa's Estate 计算凸包+判断点在线段上
- POJ 1228 Grandpa's Estate 【计算几何:凸包,andrew】
- 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 凸包模板题
- poj 1228 Grandpa's Estate[稳定凸包]
- POJ 1228 Grandpa's Estate (稳定凸包)
- POJ 1228 || Grandpa's Estate(凸包andrew算法
- POJ 1228 Grandpa's Estate (凸包)
- [POJ 1228] Grandpa's Estate · 凸包
- POJ 1228 Grandpa's Estate(确定凸包)
- 【凸包性质】 POJ 1228 Grandpa's Estate
- GUI Design Studio系列教程
- 【转载】VS2005单步调试变量错误解决方法
- 在windows环境下基于sublime text3的node.js开发环境搭建
- Fragment(碎片)的使用(左标题右内容实现)
- 第11周项目1-2
- POJ 1228 Grandpa's Estate 计算凸包+判断点在线段上
- skynet的学习过程
- 质数中的质数(质数筛法)
- 图片显示几秒,自动转换界面
- 在左移的递减数组中查找某数 【微软面试100题 第四十八题】
- 阿里云CentOs安装jdk/mysql/tomcat综合篇
- 静态代码块执行顺序
- 关于文件预览的功能实现
- (六)storm-kafka源码走读之PartitionManager