POJ 1228 —— “稳定”凸包

POJ 1228 Grandpa's Estate

这是个好题目,同时也是个不和谐的题目(不和谐原因是题目出的存在漏洞,数据弱,而且有些条件没给清楚,为了一个SB错误无限WA之后,终于AC)

 

题意就废了我好长时间,唉……英语不好的鸭梨大……

大意就是爷爷留了块土地给我,然而这块土地是以一些钉子来界定的,题目要做的就是给你一堆钉子的坐标(也就是凸包上部分的点),然后问你能不能唯一确定这块土地。

问了下度娘,这个问题叫做“稳定”凸包问题,那么首先就要了解下“稳定”凸包的性质:(在此感谢XDruid博主)

比方说有4个点:

这4个点可以围成一个凸包,但是原始的凸包可能并不是这个样子的

例如可能是这个样子:

这样我们则称这4个点确定的凸包是”不稳定“的!

那么怎么样才叫稳定呢?

是这个样子:想一想,若像刚才一样,在直线外面加一个点,那么线上的点必定不会属于凸包,要删掉,是吧?

如此以来,问题就很明确了,算法也随之而来了:

我们已经知道了怎么求凸包了(前提),这样一来,只要判断是否有3点或N>=3点共线就可以了~~

表示用的是Graham的变种Andrew……感觉真的很好用:

下面贴代码:

View Code
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;

const double EPS = 1e-6;

struct point{
    double x , y;
} p[1010] , chn[1010];

bool cmp (point a , point b)
{
     return (a.y < b.y || (a.y == b.y && a.x < b.x));
}

double xmult(point p1 , point p2 , point p3)
{
     return ((p1.x - p3.x) * (p2.y - p3.y) - (p1.y - p3.y) * (p2.x - p3.x));
}

int andrew(int n)
{
    int len , top = 1;
    chn[0] = p[0];
    chn[1] = p[1];
    for (int i = 2 ; i < n ; i ++)
    {
        while (top && xmult(p[i] , chn[top] , chn[top - 1]) > EPS) top --;
        chn[++ top] = p[i];
    }
    len = top;
    chn[++ top] = p[n - 2];
    for (int i = n - 3 ; i >= 0 ; i --)
    {
        while (top != len && xmult(p[i] , chn[top] , chn[top - 1]) > EPS) top --;
        chn[++ top] = p[i];
    }
    return top;
}

bool judge(int n)  //解释请看下面
{
     for (int i = 1 ; i < n ; i ++)
     {
         if ((xmult(chn[i - 1] , chn[i] , chn[i + 1]) != 0) && (xmult(chn[i] , chn[i + 1] , chn[i + 2]) != 0))
           return false;
     }
     return true;
}
     
int main()
{
    int T , n;
    scanf("%d" , &T);
    while (T --)
    {
          scanf("%d" , &n);
          for (int i = 0 ; i < n ; i ++) scanf("%lf%lf" , &p[i].x , &p[i].y);
          if (n < 6) printf("NO\n");
          else
          {
              sort(p , p + n , cmp);
              int top = andrew(n);
              if (judge(top)) printf("YES\n");
              else printf("NO\n");
          }
    }
    return 0;
}

写了这个题后,对凸包的理解真是加深了。

同时,在被WA了N此后(主要是因为读入数据要用double。但是题目上说是整点啊!不明白,如果没看到别人的解题报告,估计要一直WA下去)

昨晚在无限WA后找了XxX师兄,开始以为思路错了,经过他的问答,对这个题目的理解更是加深了!

下面说下代码中【judge】函数的判断原因:

理论支持:叉积 = 0 说明共线!

我们用Andrew算法求出凸包后(栈内不删去共线的点)这些点已经是按一定顺序排好了的~

然后之需要对栈内的点进行叉积判断就可以了~~ 只有当向左与向中间扩展都不满足是,才说明当前点不满足!

所以只要有一个不满足,则说明全部不满足了。

 

做了这个题目,我对之前提出的疑问有了答案。哈哈~~

posted on 2013-02-07 17:20  Hmm  阅读(356)  评论(0编辑  收藏  举报

导航