zoukankan      html  css  js  c++  java
  • 区间划分操作

    区间划分操作

             输入几个区间,根据已知区间的边界,划分成更小的区间,比如有区间:

    [1,1] [2,2] [3,8] [5,7] [7,9]

             我们希望重新划分得到的结果为:

    [1,1] [2,2] [3,5] [5,7] [7,7] [7,8] [8,9]

             我们的基本做法是首先定义边界结构体,边界分为两种情况:左边界和右边界。

             区间划分函数,我们是首先按照各个边界在数轴上的排序,从小到大依次排列,然后顺序检测当前区间边界为左边界还是右边界,然后再检测上一个边界是左边界还是右边界。根据各种情况进行相应的操作。

             程序中,我们的区间划分函数有两个版本,其中第二个版本是严格按照上述思想进行的实现。第一个版本,同样是想记录上一个边界,但是我们还设定了UNKNOWN状态,既然是记录上一个边界,那么状态只有LEFT和RIGHT两种状态,不可能有UNKNOWN状态。这里的UNKNOWN其实是指未来下一个边界的状态。我们用来记录上一个边界的变量充当了两个角色:上一个边界和未来下一个边界。但是,实质上完全可以由只记录上一个边界来替代。

             该算法首先对原来的边界进行了排序,排序的时间复杂度为O(NlogN),其中N为区间个数,进行当前边界和上一个边界状态的检测操作是一个循环,其时间复杂度为O(N),N为区间个数。所以总的时间复杂度为O(NlogN),N为区间个数。

             具体细节详见程序和注释。

    // 区间划分
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cassert>
    using namespace std;
    
    const int LEFT    = 1;
    const int RIGHT   = 2;
    const int UNKNOWN = 0;
    
    class Border
    {
    private:
        double bor;
        int    mark;
    
    public:
        Border(double d = 0.0, int m = LEFT) : bor(d), mark(m) {}
        double Bor() const
        {
            return bor;
        }
        int Mark() const
        {
            return mark;
        }
    
        friend bool operator <  (const Border& lhs, const Border& rhs);
        friend bool operator == (const Border& lhs, const Border& rhs);
    };
    
    bool operator < (const Border& lhs, const Border& rhs)
    {
        if (lhs.bor < rhs.bor)
        {
            return true;
        }
        else if (lhs.bor == rhs.bor && lhs.mark < rhs.mark)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    bool operator == (const Border& lhs, const Border& rhs)
    {
        return lhs.bor == rhs.bor && lhs.mark == rhs.mark;
    }
    
    void ReadIntervals(vector<Border>& itvs)
    {
        itvs.clear();
        double a = 0.0, b = 0.0;
        while (cin >> a >> b)
        {
            assert(a <= b);
            itvs.push_back(Border(a, LEFT));
            itvs.push_back(Border(b, RIGHT));
        }
    }
    
    void PrintRawIntervals(const vector<Border>& itvs)
    {
        for (auto i = 0; i < itvs.size() - 1; i += 2)
        {
            cout << '[' << itvs[i].Bor() << ',' << itvs[i + 1].Bor() << ']' << ' ';
        }
        cout << endl;
    }
    
    void Repartition(const vector<Border>& itvs, vector<Border>& rep)
    {
        assert(itvs.size() > 0 && itvs.size() % 2 == 0);
        vector<Border> bef(itvs);
        rep.clear();
    
        sort(bef.begin(), bef.end());
    
        int bor  = bef[0].Bor();
        int mark = bef[0].Mark();
        rep.push_back(Border(bor, mark));
        for (auto i = 1; i < bef.size(); ++i)
        {
            if (bef[i].Mark() == RIGHT) // 如果当前是右界
            {
                if (mark == LEFT) // 前一个边界为LEFT
                {
                    // 直接将当前边界保存
                    // 但是不知道该界是否是LEFT还是RIGHT
                    rep.push_back(bef[i]);
                    bor  = bef[i].Bor();
                    mark = UNKNOWN;
                }
                else if (mark == RIGHT) // 如果前一个边界为RIGHT
                {
                    // 这种情况不考虑
                    // 因为不会出现
    
                    // 如果删除UNKNOWN,可以用RIGHT代替
                    // 如果用RIGHT是表示上一个的状态
                    // 如果用UNKNOWN是表示将来的状态
                }
                else if (mark == UNKNOWN)
                {
                    // 当前为RIGHT,前一个未知,则可以推算前一个为LEFT
                    rep.push_back(Border(bor, LEFT));
                    rep.push_back(bef[i]);
                    bor  = bef[i].Bor();
                    mark = UNKNOWN;
                }
            }
            else if (bef[i].Mark() == LEFT) // 当前为左界
            {
                if (mark == LEFT) // 之前也为LEFT
                {
                    // 将当前作为右界保存
                    // 保存当前界
                    // 记录当前界
                    rep.push_back(Border(bef[i].Bor(), RIGHT));
                    rep.push_back(bef[i]);
                    mark = LEFT;
                    bor  = bef[i].Bor();
                }
                else if (mark == RIGHT) // 上一个为右界
                {
                    // 保存当前
                    // 记录当前
                    rep.push_back(bef[i]);
                    mark = LEFT;
                    bor  = bef[i].Bor();
                }
                else if (mark == UNKNOWN) // 上一个未知
                {
                    // 保存当前
                    // 记录当前
                    rep.push_back(bef[i]);
                    mark = LEFT;
                    bor  = bef[i].Bor();
                }
            }
        }
    }
    
    // 重写区间划分函数,严格按照LEFT、RIGHT两种状态
    void Repartition2(const vector<Border>& itvs, vector<Border>& rep)
    {
        assert(itvs.size() > 0 && itvs.size() % 2 == 0);
        vector<Border> bef(itvs);
        rep.clear();
    
        sort(bef.begin(), bef.end());
    
        int premark = bef[0].Mark();
        int prebor  = bef[0].Bor();
        rep.push_back(bef[0]);
    
        for (auto i = 1; i != bef.size(); ++i)
        {
            if (bef[i].Mark() == LEFT) // 如果当前为左界
            {
                if (premark == RIGHT) // 如果上一个为右界
                {
                    // 将当前保存,修改上一个
                    rep.push_back(bef[i]);
                    premark = bef[i].Mark();
                    prebor  = bef[i].Bor();
                }
                else if (premark == LEFT) // 如果上一个为左界
                {
                    // 将当前作为右界保存
                    // 并保存当前为左界
                    // 修改上一个
                    rep.push_back(Border(bef[i].Bor(), RIGHT));
                    rep.push_back(bef[i]);
                    premark = bef[i].Mark();
                    prebor  = bef[i].Bor();
                }
                else
                {
                    ;
                }
            }
            else if (bef[i].Mark() == RIGHT) // 如果当前为右界
            {
                if (premark == LEFT) // 如果上一个为左界
                {
                    // 将当前保存
                    // 修改上一个
                    rep.push_back(bef[i]);
                    premark = bef[i].Mark();
                    prebor  = bef[i].Bor();
                }
                else if (premark == RIGHT) // 如果上一个为右界
                {
                    // 将上一个作为左界保存
                    // 并将当前保存
                    // 保存下一个
                    rep.push_back(Border(prebor, LEFT));
                    rep.push_back(bef[i]);
                    premark = bef[i].Mark();
                    prebor  = bef[i].Bor();
                }
                else
                {
                    ;
                }
            }
            else
            {
                ;
            }
        }
    }
    
    // 输出规则化的区间
    void PrintRegularIntervals(const vector<Border>& rep)
    {
        for (auto i = 0; i < rep.size(); ++i)
        {
            if (rep[i].Mark() == LEFT)
            {
                cout << '[' << rep[i].Bor() << ',';
            }
            else if (rep[i].Mark() == RIGHT)
            {
                cout << rep[i].Bor() << ']' << ' ';
            }
            else
            {
                cout << '*' << rep[i].Bor() << '*';
            }
        }
        cout << endl;
    }
    
    int main()
    {
        vector<Border> itvs;
        ReadIntervals(itvs);
        PrintRawIntervals(itvs);
        PrintRegularIntervals(itvs);
    
        cout << endl;
    
        vector<Border> rep;
        Repartition2(itvs, rep);
        PrintRawIntervals(rep);
        PrintRegularIntervals(rep);
    
        return 0;
    }

  • 相关阅读:
    info plist各个功能的详解
    打个测试包弄成连接供别人下载测试
    封装的数据请求加上风火轮的效果
    福大软工 · BETA 版冲刺前准备(团队)
    福大软工 · 第十一次作业
    Alpha 冲刺 (10/10)
    Alpha 冲刺 (9/10)
    Alpha 冲刺 (8/10)
    Alpha 冲刺 (7/10)
    Alpha 冲刺 (6/10)
  • 原文地址:https://www.cnblogs.com/unixfy/p/3468209.html
Copyright © 2011-2022 走看看