NYOJ78 圈水池(简单凸包)

 

圈水池

时间限制:3000 ms  |  内存限制:65535 KB
难度:4
 
描述
有一个牧场,牧场上有很多个供水装置,现在牧场的主人想要用篱笆把这些供水装置圈起来,以防止不是自己的牲畜来喝水,各个水池都标有各自的坐标,现在要你写一个程序利用最短的篱笆将这些供水装置圈起来!(篱笆足够多,并且长度可变)
 
输入
第一行输入的是N,代表用N组测试数据(1<=N<=10)
第二行输入的是m,代表本组测试数据共有m个供水装置(3<=m<=100)
接下来m行代表的是各个供水装置的横纵坐标
输出
输出各个篱笆经过各个供水装置的坐标点,并且按照x轴坐标值从小到大输出,如果x轴坐标值相同,再安照y轴坐标值从小到大输出
样例输入
1
4
0 0
1 1
2 3
3 0
样例输出
0 0
2 3
3 0


 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 struct point
 8 {
 9     int x;
10     int y;
11 }p[105], s[105];
12 
13 bool cmp(point a, point b)
14 {
15     return a.x < b.x || (a.x == b.x && a.y < b.y);
16 }
17 
18 /*
19 int dis(point a, point b)
20 {
21     return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
22 }
23 */
24 
25 bool judge(point a, point b, point c)
26 {
27     int abx = b.x-a.x;
28     int aby = b.y-a.y;
29     int acx = c.x-a.x;
30     int acy = c.y-a.y;
31     if(abx*acy - aby*acx > 0)  // a、b、c成逆时针
32         return true;
33     return false;
34 }
35 
36 int main()
37 {
38     int T, n, top, t;
39     scanf("%d", &T);
40     while(T--)
41     {
42         scanf("%d", &n);
43         for(int i = 0; i < n; ++i)
44             scanf("%d%d", &p[i].x, &p[i].y);
45         sort(p, p+n, cmp);
46 
47         top = 0;
48         for(int i = 0; i < n; ++i)  //求下凸包
49         {
50             while(top >= 2 && !judge(s[top-2], s[top-1], p[i]))
51                 top--;
52             s[top++] = p[i];
53         }
54         t = top-1;
55         for(int i = n-1; i >= 0; --i)  // 求上凸包
56         {
57             while(top >= t+2 && !judge(s[top-2], s[top-1], p[i]))
58                 top--;
59             s[top++] = p[i];
60         }
61         --top;  // 下凸包和上凸包的首尾点肯定是重叠的,所以删去
62 
63         sort(s, s+top, cmp);
64         for(int i = 0; i < top; ++i)
65             printf("%d %d\n", s[i].x, s[i].y);
66     }
67     return 0;
68 }
原文地址:https://www.cnblogs.com/dongsheng/p/3065541.html