Merge Rectanles

265 篇文章 1 订阅
9 篇文章 0 订阅

From  http://codercareer.blogspot.com/2011/12/no-27-area-of-rectangles.html


No. 27 - Area of Rectangles

Problem: Please implement a function which gets area of a set of rectangles, whose edges are parallel to X-axis or Y-axis.

Rectangles are defined as the following:
/* === Assumming: left <= right; top <= bottom === */
struct Rect
{
     int left;
     int right;
     int top;
     int bottom;
};

Analysis: The merged shape of overlapping rectangles is no longer a rectangle, and there is no equation to calculate the merged area directly. Therefore, we should split it into a set of rectangles.

A solution to split overlapping rectangles is based on x-values of all left and right edges. For example, there are three rectangles in Figure 1.


We get all x-values of the three rectangles, which are X1, X2, …, X6 in Figure 2, and then split the merged shape into five rectangles based on x-values.

We should merge y-values of rectangles in ranges of x-value. For instance, both Rect1 and Rect2 fill into the x-value range between X2 and X3. Therefore, we should merge the y-value range of Rect1 and Rect2 to calculate the rectangle piece between X2 and X3.


Since ranges of x-values and y-values are necessary information to calculate area, we can define a class Range: 

struct Range
{
     int less;
     int greater;

    Range( int l,  int g)
    {
        less = (l < g) ? l : g;
        greater = (l + g) - less;
    }

     bool IsOverlapping( const Range& other)
    {
         return !(less > other.greater || other.less > greater);
    }

     void Merge( const Range& other)
    {
         if(IsOverlapping(other))
        {
            less = (less < other.less) ? less : other.less;
            greater = (greater > other.greater) ? greater : other.greater;
        }
    }
};

The overall algorithm to calculate the area of overlapping rectangles is: We firstly get all x-values of all rectangles, and then check whether every rectangle fills into each range formed by two neighboring x-values. If there are multiple rectangles fill into an x-value range, we merge their ranges of y-value before we calculate the area of a piece of merged rectangle.

The following function GetArea implements this algorithm. For optimization purpose, we sort all input rectangles according to their x-values of right edges, and sort a vector of all x-values.

int GetArea(vector<Rect>& rects)
{
     // sort rectangles according to x-value of right edges
    sort(rects.begin(), rects.end());

    vector< int> xes;
    GetAllX(rects, xes);
    sort(xes.begin(), xes.end());

     int area = 0;
    vector< int>::iterator iterX1 = xes.begin();
    vector<Rect>::const_iterator iterRect = rects.begin();
     for(; iterX1 != xes.end() && iterX1 != xes.end() - 1; ++ iterX1)
    {
        vector< int>::iterator iterX2 = iterX1 + 1;

         // filter out duplicated X-es
         if(*iterX1 < *iterX2)
        {
            Range rangeX(*iterX1, *iterX2);

             while(iterRect->right < *iterX1)
                ++ iterRect;

            list<Range> rangesOfY;
            GetRangesOfY(rects, iterRect, rangeX, rangesOfY);
            area += GetRectArea(rangeX, rangesOfY);
        }
    }

     return area;
}

bool  operator < ( const Rect& rect1,  const Rect& rect2)
{
     return (rect1.right < rect2.right);
}

The following function GetAllX gets all x-values of all input rectangles.

void GetAllX( const vector<Rect>& rects, vector< int>& xes)
{
    vector<Rect>::const_iterator iter = rects.begin();
     for(; iter != rects.end(); ++ iter)
    {
        xes.push_back(iter->left);
        xes.push_back(iter->right);
    }
}

The function GetRangesOfY gets the ranges of y-values which fill into a range of x-value. It should be noticed that there might be multiple non-overlapping rectangles fill into an x-value range. For example, Rect1 and Rect2 in Figure do not overlap with each other. Therefore, we cannot merge their ranges of y-values. That is why it has a list of ranges of y-values for a range of x-value in the function GetRangesOfY.



void  GetRangesOfY( const  vector<Rect>& rects, vector<Rect>::const_iterator iterRect,  const  Range& rangeX, list<Range>& rangesOfY)
{
     for(; iterRect != rects.end(); ++ iterRect)
    {
         if(rangeX.less < iterRect->right && rangeX.greater > iterRect->left)
            InsertRangeY(rangesOfY, Range(iterRect->top, iterRect->bottom));
    }
}

The function InsertRangeY inserts a range of y-value into a list. When the range overlaps with another range existing in the list, we should remove the existing range and then insert a new merged range.

void InsertRangeY(list<Range>& rangesOfY, Range& rangeY)
{
    list<Range>::iterator iter = rangesOfY.begin();
     while(iter != rangesOfY.end())
    {
         if(rangeY.IsOverlapping(*iter))
        {
            rangeY.Merge(*iter);

            list<Range>::iterator iterCopy = iter;
            ++ iter;
            rangesOfY.erase(iterCopy);
        }
         else
            ++ iter;
    }

    rangesOfY.push_back(rangeY);
}

The function GetRectArea below gets the total area of all rectangle pieces in a range of x-value.

int GetRectArea( const Range& rangeX,  const list<Range>& rangesOfY)
{
     int width = rangeX.greater - rangeX.less;
   
    list<Range>::const_iterator iter = rangesOfY.begin();
     int area = 0;
     for(; iter != rangesOfY.end(); ++ iter)
    {
         int height = iter->greater - iter->less;
        area += width * height;
    }

     return area;
}

The author Harry He owns all the rights of this post. If you are going to use part of or the whole of this ariticle in your blog or webpages,  please add a reference to http://codercareer.blogspot.com/. If you are going to use it in your printed books, please contact me (zhedahht@gm

My code:

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <limits.h>
#include <assert.h>
#include <stdio.h>
using namespace std;


class Rec {
 public:
  double ltx, lty, rdx, rdy;
  Rec(double x1 = 0, double y1 = 0, double x2 = 0, double y2 = 0): ltx(x1), lty(y1), rdx(x2), rdy(y2){
  }
};
class Inte {
public:
  double s, e;  
  Inte(double s1 = 0, double e1 = 0) : s(s1), e(e1) {
  }
};
class cmp1 {
 public:
  bool operator()(const Inte& inte1, const Inte& inte2) const{
    return inte1.s == inte2.s ? inte1.e < inte2.e : inte1.s < inte2.s;
  }
};

class Solution{
 public:

  vector<Inte> merge(vector<Inte>& inte) {
    vector<Inte> res;
    if (inte.empty())
      return res;
    sort(inte.begin(), inte.end(), cmp1());

    Inte cur(inte[0].s, inte[0].e);
    int size = inte.size();
    for (int i = 1; i < size; ++i) {
      if (inte[i].s > cur.e) {
        res.push_back(cur);
        cur.s = inte[i].s, cur.e = inte[i].e;
      }
      else {
        cur.s = min(cur.s, inte[i].s);
        cur.e = max(cur.e, inte[i].e);
      }
    }
    res.push_back(cur);
    return res;
    
  }

  double calArea(vector<vector<Inte> >& inters, const vector<double>& xcoor) {
    double res = 0;
    int size = inters.size();
    for (int i = 0; i < size; ++i) {
      vector<Inte> cur = merge(inters[i]);

      int cursize = cur.size();
      for (int j = 0; j < cursize; ++j)
        res += (cur[j].e - cur[j].s)*(xcoor[i+1]-xcoor[i]);
    }
    return res;
  }
  double calAllArea(const vector<Rec>& recs) {
    int i, size = recs.size(), j, intesize;
    vector<double> xcoor;
    
    for (i = 0; i < size; ++i) {
      xcoor.push_back(recs[i].ltx);
      xcoor.push_back(recs[i].rdx);
    }
    sort(xcoor.begin(), xcoor.end());
    xcoor.resize(unique(xcoor.begin(), xcoor.end()) - xcoor.begin());
    intesize = xcoor.size() - 1;
    vector<vector<Inte> > inters(intesize, vector<Inte>(0));
    
    
    for (i = 0; i < size; ++i) {
      int j1 = lower_bound(xcoor.begin(), xcoor.end(), recs[i].ltx) - xcoor.begin();
      int j2 = upper_bound(xcoor.begin(), xcoor.end(), recs[i].rdx) - xcoor.begin();
      for (j = j1; j <= j2 -2; ++j) {
        inters[j].push_back( Inte(recs[i].rdy, recs[i].lty));
      }
    }
    double res = calArea(inters, xcoor);
    return res;
  }
};
int main()
{
  Solution s;
  freopen("E://test.txt","r",stdin);
  vector<Rec> recs;
  int k, count = 0;
  double x1, x2, y1, y2;
  while (scanf("%d", &k) && k != 0) {
    recs.clear();
    printf("Test case #%d\n", ++count);
    while (k--) {
      scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
      recs.push_back(Rec(x1, y2, x2, y1));
    }
    double res = s.calAllArea(recs);
    printf("Total explored area: %.2f \n", res);
  }
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值