nyist-78 圈水池(建立凸包)

题目链接:传送门

78-圈水池

内存限制:64MB 时间限制:3s Special Judge: No

accepted:1 submit:1

题目描述:
有一个牧场,牧场上有很多个供水装置,现在牧场的主人想要用篱笆把这些供水装置圈起来,以防止不是自己的牲畜来喝水,各个水池都标有各自的座标,现在要你写一个程序利用最短的篱笆将这些供水装置圈起来!(篱笆足够多,并且长度可变)

输入描述:
第一行输入的是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

思路:建立凸包。先排序,从小到大(也可以从大到小),可以将过程分为两步,先建立上半部分,再建立下半部分(思想是一样的),因为排完序后开头和结尾的两个点是一定有的,所以从开始点开始,查找差积小于等于0的(或者大于等于0的,这只是方向的问题,不影响结果),下半部分也是这样。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int maxn=109;
struct node
{
    int x,y;
}edge[maxn],ans[maxn];

bool cmp(node a,node b)
{
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}
int mul(node a,node b,node c)//计算差积
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}

int solve(int n)
{
    int len=0;
    for(int i=0;i<n;i++)//计算上半部分
    {
        while(len>1&&mul(ans[len-2],ans[len-1],edge[i])<=0) len--;
        ans[len++]=edge[i];
    }
    int k=len;
    for(int i=n-1;i>=0;i--)//计算下半部分
    {
        while(len>k&&mul(ans[len-2],ans[len-1],edge[i])<=0) len--;
        ans[len++]=edge[i];
    }
    return len-1;//最后一个是开始点(开始点被记录了两次)
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d",&edge[i].x,&edge[i].y);

        sort(edge,edge+n,cmp);//排序

        int len=solve(n);
        sort(ans,ans+len,cmp);
        for(int i=0;i<len;i++)
            printf("%d %d\n",ans[i].x,ans[i].y);
    }
    return 0;
}
发布了186 篇原创文章 · 获赞 14 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章