zoukankan      html  css  js  c++  java
  • “稳定”凸包poj1228

       题目链接: http://poj.org/problem?id=1228

       这道题算是很好的一道凸包的题吧,做完后会加深对凸包的理解。

       题意很关键。。。这英语看了好几遍才差不多看明白了。意思就是给你一堆点,这堆点本来就是某个凸包上的部分点,问你这堆点是否能确定唯一的凸包(大概这意思吧。。。)。后来搜了一下,发现这种凸包叫做稳定凸包。

       首先来了解什么是稳定的凸包。比如有4个点:

    这四个点是某个凸包上的部分点,他们连起来后确实还是一个凸包。但是原始的凸包可能不是这样。比如:

    即这四个点构成的凸包不算做“稳定”的。我们发现,当凸包上存在一条边上的点只有端点两个点的时候,这个凸包不是稳定的,因为它可以在这条边外再引入一个点,构成一个新的凸包。但一旦一条边上存在三个点,那么不可能再找到一个点使它扩展成一个新的凸包,否则构成的新多边形将是凹的。

    下面是一个典型的稳定凸包:

           那么这道题的做法终于明确了。即求出给定这堆点的新的凸包,然后判断凸包上的每条边上是否至少有3个点存在,假如有一条边不符合条件,则输出NO。否则YES。

         写的时候又遇到几个小问题了。。。一个是要修改一下凸包模板,大多数人的模板都是不包括共线点的。然后,如果输入的点数n小于6,那么直接输出NO。当然,也可以直接按极角排序进行比较。至于判断一条边上是否至少有三个点,我是这样做的,假设要判断的边i,那么判断边i和边i-1,边i和边i+1的夹角是否都为0(180)。

        代码~:

     1 //POJ--1228
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cmath>
     5 #include <cstring>
     6 #include <algorithm>
     7 #define  eps 1e-8
     8 using namespace std;
     9 
    10 struct  point
    11 {
    12     double x,y;
    13 };
    14 point p[1010],stack[1010];
    15 int N,top;
    16 
    17 double multi(point p1, point p2, point p3)  
    18 {
    19     return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
    20 }
    21 
    22 double dis(point a, point b)
    23 {
    24     return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    25 }
    26 
    27 int cmp(const void *a, const void *b)
    28 {
    29     point c = *(point *)a;
    30     point d = *(point *)b;
    31     double k = multi(p[0], c, d);
    32     if(k < 0 || (!k && dis(c, p[0]) > dis(d, p[0])))    return 1;
    33     return -1;
    34 }
    35 
    36 void Convex()
    37 {
    38     for(int i = 1; i < N; i++)
    39     {
    40         point temp;
    41         if(p[i].y < p[0].y || ( p[i].y == p[0].y && p[i].x < p[0].x))
    42         {
    43             temp = p[i];
    44             p[i] = p[0];
    45             p[0] = temp;
    46         }
    47     }
    48     qsort(p + 1, N - 1, sizeof(p[0]), cmp);
    49     stack[0] = p[0];
    50     stack[1] = p[1];
    51     top = 1;
    52     for(int i = 2; i < N; i++)     
    53     {
    54         while(top >= 1 && multi(stack[top - 1], stack[top], p[i]) < 0)     top--;         //共线的点也压入凸包内;
    55         top++;
    56         stack[top] = p[i];
    57     }
    58 }
    59 
    60 bool judge()
    61 {
    62     for(int  i=1;i<top;i++)
    63     {
    64         if((multi(stack[i-1],stack[i+1],stack[i]))!=0&&(multi(stack[i],stack[i+2],stack[i+1]))!=0)          //判断每条边是否有至少三个点;
    65             return false;
    66     }
    67     return true;
    68 }
    69 
    70 int main()
    71 {
    72     int t;
    73     cin>>t;
    74     while(t--)
    75     {
    76         cin>>N;
    77         for(int i=0;i<N;i++)
    78         scanf("%lf%lf",&p[i].x,&p[i].y);
    79         if(N<6)   puts("NO");
    80         else 
    81         {
    82                 Convex();
    83                 if(judge())  puts("YES");
    84                 else puts("NO");
    85         }
    86     }
    87     return 0;
    88 }

     

  • 相关阅读:
    怎样修改原型对象prototype
    怎样获取构造函数的名字
    怎样把实例对象当构造函数用
    怎样理解prototype对象的constructor属性
    怎样理解构造函数的原型对象prototype
    怎样给回调函数绑定this
    怎样绑定this
    怎样理解数组的空元素empty与undefined的区别
    怎样找出数组中的最大数值
    怎样调用对象的原生方法
  • 原文地址:https://www.cnblogs.com/xdruid/p/2555536.html
Copyright © 2011-2022 走看看