计算几何凸包——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
来源
[张洁烽]原创
上传者

张洁烽


介绍一下用到的凸包思想

什么是凸包? 
假设平面上有p0~p12共13个点,过某些点作一个多边形,使这个多边形能把所有点都“包”起来。当这个多边形是凸多边形的时候,我们就叫它“凸包”。

首先,找一个凸包上的点,把这个点放到第一个点的位置P0。然后把P1~Pm 按照P0Pi的方向排序,可以用矢量积(叉积)判定。

做好了预处理后开始对堆栈中的点<p3,p4,...,pm>中的每一个点进行迭代,在第7到8行的while循环把发现不是凸包中的顶点的点从堆栈中移去。(原理:沿逆时针方向通过凸包时,在每个顶点处应该向左转。因此,while循环每次发现在一个顶点处没有向左转时,就把该顶点从堆栈中弹出。)当算法向点pi推进、在已经弹出所有非左转的顶点后,就把pi压入堆栈中。

举例如下:

                            

                                  

                            

                                 

                                  

                                                        

#include<iostream>
#include<algorithm>
using namespace std;
struct point
{
    double x,y;
}p[300],s[300];//点
int cmp(point a,point b)
{
    if(a.x==b.x)
        return a.y<b.y;
   else  return a.x<b.x;
}
bool judge(point a, point b, point c)//ab×ac叉乘
{
    int abx = b.x-a.x;
    int aby = b.y-a.y;
    int acx = c.x-a.x;
    int acy = c.y-a.y;
    if(abx*acy - aby*acx > 0)
        return true;
    return false;
}
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int m;
        cin>>m;
        for(int i=0;i<m;i++)
        cin>>p[i].x>>p[i].y;
       // cout<<endl;
        sort(p,p+m,cmp);
         //for(int j=0;j<m;j++)
           // cout<<p[j].x<<" "<<p[j].y<<endl;
          //  cout<<endl;
        int top=0;
        for(int i=0;i<m;i++)
        {
            while(top>=2&&!judge(s[top-2],s[top-1],p[i]))
                top--;
            s[top++]=p[i];
        }
       // for(int j=0;j<top;j++)
           // cout<<s[j].x<<" "<<s[j].y<<endl;
          //  cout<<endl;
        int t=top-1;
        for(int i=m-1;i>=0;i--)
        {
            while(top>=t+2&&!judge(s[top-2],s[top-1],p[i]))
                top--;
            s[top++]=p[i];
        }
        --top;//上凸包和下凸包首尾重复
        sort(s,s+top,cmp);
        for(int j=0;j<top;j++)
            cout<<s[j].x<<" "<<s[j].y<<endl;
    }
    return 0;
}

参考链接 点击打开链接
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值