“稳定”凸包----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 }

 

 

 

 

 

 

posted @ 2012-06-20 00:55  XDruid  阅读(2101)  评论(1编辑  收藏  举报