程序最美(寻路)

你还在坚持练习你的技术吗?运动员天天训练,音乐家也会演练更难的曲章。你呢?

区间划分操作

区间划分操作

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

[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;
}

posted on 2013-12-10 21:23  unixfy  阅读(1148)  评论(0编辑  收藏  举报

导航