算法作业17

题目地址https://leetcode.com/problems/erect-the-fence/#/description

题目描述:There are some trees, where each tree is represented by (x,y) coordinate in a two-dimensional garden. Your job is to fence the entire garden using the minimum length of rope as it is expensive. The garden is well fenced only if all the trees are enclosed. Your task is to help find the coordinates of trees which are exactly located on the fence perimeter.

我的代码

/**
 * Definition for a point.
 * struct Point {
 *     int x;
 *     int y;
 *     Point() : x(0), y(0) {}
 *     Point(int a, int b) : x(a), y(b) {}
 * };
 */
class Solution {
public:
    static bool mycmp11(Point &p,Point &q){
        int a = q.x-p.x;
        if(a==0) a=q.y-p.y;
        return a<0;
    }
    void outerHalf(vector<Point>& points,vector<Point>& hp,int dis){
        int s=0,t=points.size()-1;
        if(dis<0){
            s=s+t;
            t=s-t;
            s=s-t;
        }
        for(int i=s;dis*(t-i)>=0;i+=dis){
            hp.insert(hp.begin(),points[i]);
            while(hp.size()>=3&&((hp[2].x-hp[1].x)*(hp[1].y-hp[0].y)>(hp[1].x-hp[0].x)*(hp[2].y-hp[1].y))){
                hp.erase(hp.begin()+1);
            }

        } 
    }
    vector<Point> outerTrees(vector<Point>& points) {
        sort(points.begin(),points.end(),mycmp11);//return points;
        vector<Point> lp,up;
        outerHalf(points,lp,1);
        outerHalf(points,up,-1);//return up;
        if(points.size()<3||(lp.size()==up.size()&&lp[1].x==up[up.size()-2].x&&lp[1].y==up[up.size()-2].y)) return lp;
        int n=up.size()-1;
        for(int i=1;i<n;i++) lp.push_back(up[i]);
        return lp;
    }
};

解题思路
由简单的数学知识可知题目所求的边界一定是凸多边形,直线和点可以看做是退化的凸多边形。
所有我们所要求的就是最大的凸多边形上面的点。
而对于一个凸多边形,从最左下方和最右上方这两个不同点断开得到两条折线,从顺时针方向看这两条折现上的线段的斜率是递减的,从逆时针其斜率是递增的。反过来看,当一个多边形满足这一条件时,它是凸多边形。
现在再来看这个题目,容易知道,我们要求的就是最大的凸多边形,那么,我们首先可以找到这两个点,然后分别以这两个点为起点按顺时针或逆时针进行遍历来构造这两条折线。
很显然的一点是,题目所有的点中最左下方的点和最右上方的点是一定包括在最终的多边形里面的,所以,很自然的,这两个点也是最终多边形的最左下方的点和最右上方的点。因此,首先将points中的所有点按照从左下到右上的顺序排列(x小的靠前,x相同时y小的靠前);然后对points从前往后遍历得到一条边界,从后往前遍历得到另一条边界。即按顺时针找到最大的凸多边形的上面和下面的折现。遍历的方式也就是遵循斜率递减的原则。
最后,找到两条折线后,判断是否重合(直线),然后整合成多边形即可。
代码的复杂度分析包括三部分,一是排序,为O(nlogn),二是遍历,为O(n),三是整合,最坏为O(n),综合而言复杂度为O(nlogn)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值