含生存期的矩形利用率問題求解

問題描述:

已知一寬爲W高爲H的目的矩形,時間序列爲t0,t1,……,在時間tn時系統隨機產生一寬爲Wn(不超過W)高爲Hn(不超過H)的小矩形,並且需將此小矩形放至目的矩形中,而且小矩形的生存期未知(即在同一時刻,產生一個小矩形時有可能同時需銷燬若干個已存在小矩形)。尋找一算法使得在一段時間t內,目的矩形被重置的次數最少?

 

解決方案:

此問題類似於內存管理問題:隨機出現的new(或malloc)和delete(或free)分別分配和釋放內存,一段時間後,內存碎片的產生便會導致某一時刻new(或malloc)返回失敗。這裏的問題是,在產生的小矩形不能放至目的矩形時,便需要將目的矩形重置(即清空所有小矩形),求解結果爲時間t內的重置次數儘可能少。

 

考慮到生存期問題,我們需要對目的矩形的可用空間進行分配和回收。當某個小矩形銷燬時,我們將此空間重新加至可用空間中,並且儘可能拼接成更大的空間,以供下一個可能更大的小矩形使用(目的矩形左上角爲原點(0,0)),採用夥伴系統算法。

 

先定義矩形分配的相關操作

 

// 定義矩形的小於操作符“<”,按從左至右,從上至下的順序排列

inline bool operator<(RECT const& lhs, RECT const& rhs)

{

    return (lhs.top < rhs.top || (lhs.top == rhs.top && lhs.left < rhs.left));

}

 

// 如果使用的是STL,也可以特化模板類std::less

template<>

struct std::less<RECT>

{

    bool operator()(RECT const& lhs, RECT const& rhs) const

    {

        return (lhs.top < rhs.top || (lhs.top == rhs.top && lhs.left < rhs.left);

    }

}

 

// 使用vecotr保存可用空間的矩形,初始狀態爲只含有一個元素且爲目的矩形

std::vecotr<RECT> rect_for_use;

rect_for_use.push_back(CRect(0, 0, W, H));

 

// 定義矩形的大於等於操作符“>=”

inline bool operator>=(RECT const& lhs, RECT const& rhs)

{

    return (lhs.right - lhs.left >= rhs.right - rhs.left && lhs.bottom - lhs.top >= rhs.bottom - rhs.top);

}

 

// 或者特化模板類std::greater_than

template<>

struct std::greater_than<RECT>

{

    bool operator()(RECT const& lhs, RECT const& rhs) const

    {

        return (lhs.right - lhs.left >= rhs.right - rhs.left && lhs.bottom - lhs.top >= rhs.bottom - rhs.top);

    }

}

 

// 從可用空間中查找一個能容下當前小矩形的空間

std::vector<RECT>::iterator it = std::find_if(rect_for_use.begin(), rect_for_use.end(), std::greater_than<RECT>());

 

// 如果未找到,重置目的矩形

if(it == rect_for_use.end())

{

    rect_for_use.erase(rect_for_use.begin(), rect_for_use.end());

    rect_for_use.push_back(CRect(0, 0, W, H));

}

 

再定義矩形回收的相關操作

 

// 查找需要插入的位置

std::vector<RECT>::iterator it = std::lower_bound(rect_for_use.begin(), rect_for_use.end(), rc, std::less<RECT>());

 

// 插入到可用空間中

it = std::insert(rect_for_use.begin(), rect_for_use.end(), it);

 

// 判斷是否需要合併成更大的空間

while(1)
{
    if(it != rect_for_use.begin())
    {
        RECT& forward = *(it - 1);
        RECT& cur = *it;
        if(forward.top == cur.top && forward.bottom == cur.bottom && forward.right == cur.left)
        {

             forward.right = cur.right;

             it = rect_for_use.erase(it);
             continue;

         }
        else if(forward.left == cur.left && forward.right == cur.right && forward.bottom == cur.top)
        {

             forward.bottom = cur.bottom;

             it = rect_for_use.erase(it);
             continue;

         }
     }
     if(++it != rect_for_use.end())
          continue;
     break;
}

 

結論:

此算法原理很簡單,實現也不復雜,在實踐中隨機情況下運行良好,並且效率較高。

 

附:實踐中回收時合併操作並不一定只發生在相鄰的兩個矩形中,可能出現跳躍合併的情況,實現也是需要一個簡單的查找而已。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章