【华为练习题】 求最大凸多边形(高级)

【华为练习题】 求最大凸多边形(高级)

题目

题目描述:
给定一些点,输出最大面积的凸边形。输出起始点为x轴最左边的点,按照顺时针方向输出,每个点必须是凸边形的顶点(不输出边上或凸边形内的点)。输入第一个数n为坐标点个数,后面依次为n个坐标点的坐标,横坐标在前,不同坐标点用‘;’隔开,相同坐标点的横纵坐标用‘,’隔开。
输入样例:
13;-4,1;-2,3;1,3;2,2;1,4;5,4;6,1;2,-4;-3,-3;1,-1;-2,-2;1,-2;-1,-1
输出样例:
-4,1;-2,3;1,4;5,4;6,1;2,-4;-3,-3
注:
- 输入数据的第一个数为点的数目,然后是分号;再后面就是以分号间隔的点;
- 点的数目最少为3个,最多为65535;
- 该题目和斜率相关。

分析

从横坐标最小的点,斜率为正无限开始,依次寻找下一个坐标点。具体过程为,求出该点与其它所有点的斜率,找到小于当前斜率的前提下能形成最大斜率且横坐标大于等于该点的点。直到找到横坐标最大的点为止。再从该点,斜率为正无限开始,依次寻找下一个坐标点。具体过程为,求出该点与其它所有点的斜率,找到小于当前斜率的前提下能形成最大斜率且横坐标小于等于该点的点。直到找到初始位置为止。

解答

#include 
#include 
#include 
#include 
using namespace std;

struct Point
{
    Point(int a, int b):x(a),y(b) {};
    int x,y;
};

// 判断字符是否为分隔符
inline bool isSperator(char c){
    return c == ',' || c == ';';
}

// 计算斜率
inline double computeK(Point p1, Point p2){
    double disX = p2.x - p1.x;
    double disY = p2.y - p1.y;
    if (disX == 0)
    {
        return disY > 0 ? INT_MAX : INT_MIN;
    }
    return disY / disX;
}

// 找到下一个符合条件的坐标点
int findNextPoint(const vector &vp, int now, double &nowK, bool &flag){
    if (flag)
    {
        int max = now + 1; 
        double maxK = computeK(vp[now],vp[max]);
        for (unsigned i = now + 2; i < vp.size(); i++)
        {
            double k = computeK(vp[now],vp[i]);
            if (k > maxK && k <= nowK)
            {
                max = i;
                maxK = k;
            }
        }
        nowK = maxK;
        return max; 
    }
    else
    {
        int max = now - 1;
        double maxK = computeK(vp[max],vp[now]);
        for (int i = now - 2; i >= 0; i--)
        {
            double k = computeK(vp[i],vp[now]);
            if (k > maxK && k <= nowK)
            {
                max = i;
                maxK = k;
            }
        }
        nowK = maxK;
        return max;
    }
}

void findPoints(const string &s, vector &result){

    // 将所有数字读入tmp中
    vector<int> tmp;
    auto begin = s.begin();
    while (begin != s.end())
    {
        if (isSperator(*begin))
        {
            begin++;
            continue;
        }
        auto ahead = begin + 1;
        while (ahead != s.end() && !isSperator(*ahead))
        {
            ahead++;
        }
        tmp.push_back(stoi(string(begin,ahead)));
        begin = ahead;
    }

    // 根据读入数据依次创建坐标点,并根据横坐标升序排序(横坐标相同则按纵坐标降序排序)
    vector vp;
    for (unsigned i = 1; i < tmp.size() - 1; i+= 2)
    {
        Point p(tmp[i],tmp[i + 1]);
        vp.push_back(p);
    }
    sort(vp.begin(),vp.end(),[](const Point &p1, const Point &p2){
        return p1.y > p2.y;
    });
    stable_sort(vp.begin(),vp.end(),[](const Point &p1, const Point &p2){
        return p1.x < p2.x;
    });

    // 顺势针依次寻找坐标点
    bool flag = true;
    double nowK = INT_MAX;
    int now = findNextPoint(vp,0,nowK,flag);
    result.push_back(vp[0]);
    while (now != 0)
    {
        if (now == vp.size() - 1)
        {
            flag = false;
            nowK = INT_MAX;
        }
        result.push_back(vp[now]);
        now = findNextPoint(vp,now,nowK,flag);
    }
}

int main()
{
    string s;
    vector result;
    cin >> s;
    findPoints(s,result);
    // 依次打印坐标点
    for (unsigned i = 0; i < result.size(); i++)
    {
        cout << result[i].x << "," << result[i].y;
        if (i != result.size()-1) cout << ";";
    }
    cout << endl;
    return 0;
}

你可能感兴趣的:(C++,C++面试总结)