经典算法 | 给定n个矩形,判断这些矩形是否在不重合的情况下组成一个大矩形的算法

GivenN axis-aligned rectangles where N > 0, determine if they all together forman exact cover of a rectangular region.

Eachrectangle is represented as a bottom-left point and a top-right point. Forexample, a unit square is represented as [1,1,2,2]. (coordinate of bottom-leftpoint is (1, 1) and top-right point is (2, 2)).

Example1:

rectangles = [

  [1,1,3,3],

  [3,1,4,2],

  [3,2,4,4],

  [1,3,2,4],

  [2,3,3,4]

]

 

Return true. All 5 rectangles together form an exact cover ofa rectangular region.

Example2:

rectangles = [

  [1,1,2,3],

  [1,3,2,4],

  [3,1,4,2],

  [3,2,4,4]

]

 

Return false. Because there is a gap between the tworectangular regions.

Example3:

rectangles = [

  [1,1,3,3],

  [3,1,4,2],

  [1,3,2,4],

  [3,2,4,4]

]

 

Return false. Because there is a gap in the top center.

Example4:

rectangles = [

  [1,1,3,3],

  [3,1,4,2],

  [1,3,2,4],

  [2,2,4,4]

]

 

Return false. Because two of the rectangles overlap with eachother.

这一题我也没想到会这么难,这一题要求你对于给定的所有矩形,判断其是否能在不相交的情况下组成一个大矩形。


每个矩形的四个端点在大矩形中只有可能是以上三种情况的一种,



每个矩形有4个端点,并且每个端点在大矩形中有4个区域,当某个端点在这4个区域的某个区域覆盖了超过一个的时候,这个时候必有两个矩形重叠,

所有在大矩形四个端点的端点有且只有一个区域被覆盖,在大矩形四条边上的端点只能有两个区域被覆盖或者是无区域覆盖

在大矩形里面的端点只能有两个相邻区域覆盖或者是四个区域覆盖

对于输入的所有矩形,对其四个端点计算覆盖值,当所有矩形输入完毕之后,统计所有端点的覆盖值是否合法就能得到这种情况的合法性

这个技巧还能用来判断多个矩形组成的大矩形在小矩形两两覆盖合法的情况下是否有空腔的问题,但是不能用来判断多个矩形是否两两重叠


class Solution {
public:
bool setIn(int x, int y, int whatDrt, unordered_map<string, int> &mark)
{
	unordered_map<string, int> ::iterator it;
	string tmp;
	if (x == 3 && y == 1)
		int j_mark = 1;

	tmp = to_string(x) + "," + to_string(y);
	it = mark.find(tmp);
	if (it == mark.end())
	{
		mark.insert(pair <string,int>(tmp, whatDrt));
	}
	else
	{
		int t = (*it).second;
		if (((*it).second&whatDrt) != 0) 
			return false;
		(*it).second ^= whatDrt;
	}
	return true;
}
bool putOn(unordered_map<string, int> &mark,int x1,int y1,int x2,int y2)
{
	if (!setIn(x1, y1, 2, mark)) return false;
	if (!setIn(x1, y2, 8, mark)) return false;
	if (!setIn(x2, y1, 1, mark)) return false;
	if (!setIn(x2, y2, 4, mark)) return false;
	return true;
}
bool isRectangleCover(vector<vector<int>>& rectangles) {
	unordered_map <string, int> mark;
	string tmp; int x1=INT_MAX, x2=0, y1= INT_MAX, y2=0,count=0;
	for (int i = 0; i < rectangles.size(); i++)
	{
		x1 = min(x1, rectangles[i][0]);
		y1 = min(y1, rectangles[i][1]);
		x2 = max(x2, rectangles[i][2]);
		y2 = max(y2, rectangles[i][3]);
		if (!putOn(mark, rectangles[i][0], rectangles[i][1], rectangles[i][2], rectangles[i][3])) return false;
	}
	string tmp1 = to_string(x1) + ',' + to_string(y1);
	string tmp2 = to_string(x1) + ',' + to_string(y2);
	string tmp3 = to_string(x2) + ',' + to_string(y1);
	string tmp4 = to_string(x2) + ',' + to_string(y2);
	unordered_map<string, int> ::iterator it;
	for (it = mark.begin(); it != mark.end(); it++)
	{
		if ((*it).first == tmp1 || (*it).first == tmp2 || (*it).first == tmp3 || (*it).first == tmp4) { count++; continue; }
		string x = (*it).first;
		if ((*it).second == 14 || (*it).second == 13 || (*it).second == 11 || (*it).second == 7 || (*it).second == 9 || (*it).second == 6) return false;
		if ((*it).second == 1 || (*it).second == 2 || (*it).second == 4 || (*it).second == 8) return false;
	}
	if (count != 4) return false;
	return true;
}
};


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里提供一个基于贪心算法的C++2D矩形装箱算法,可以实现多个矩形的高效排版。 ``` #include <iostream> #include <vector> #include <algorithm> using namespace std; struct Rect { int id, w, h, x, y; Rect(int _id, int _w, int _h) { id = _id; w = _w; h = _h; x = y = 0; } }; bool cmp(Rect a, Rect b) { if (a.h != b.h) return a.h > b.h; return a.w > b.w; } class Bin { public: int w, h; vector<Rect> rects; Bin(int _w, int _h) { w = _w; h = _h; } bool add(Rect rect) { int x = 0, y = 0; if (!find_pos(rect, x, y)) return false; rect.x = x; rect.y = y; rects.push_back(rect); return true; } private: bool find_pos(Rect rect, int& x, int& y) { sort(rects.begin(), rects.end(), cmp); for (int i = 0; i < rects.size(); i++) { if (rect.w <= w - rects[i].x && rect.h <= h - rects[i].y) { x = rects[i].x; y = rects[i].y; for (int j = i + 1; j < rects.size(); j++) { if (rects[j].y < y + rect.h && rects[j].x < x + rect.w) { x = max(x, rects[j].x + rects[j].w); } } return true; } else if (rect.h <= w - rects[i].y && rect.w <= h - rects[i].x) { swap(w, h); for (int j = 0; j < rects.size(); j++) { if (rects[j].y < x + rect.w && rects[j].x < y + rect.h) { y = max(y, rects[j].y + rects[j].h); } } swap(w, h); swap(rect.w, rect.h); swap(x, y); if (find_pos(rect, x, y)) return true; } } return false; } }; bool cmp_area(Rect a, Rect b) { return a.w * a.h > b.w * b.h; } vector<Rect> pack_rects(int w, int h, vector<Rect>& rects) { vector<Rect> result; sort(rects.begin(), rects.end(), cmp_area); Bin bin(w, h); for (int i = 0; i < rects.size(); i++) { if (!bin.add(rects[i])) { cout << "Can not pack rectangle " << rects[i].id << endl; } else { result.push_back(rects[i]); } } return result; } int main() { int w = 100, h = 100, gap = 5; vector<Rect> rects; rects.push_back(Rect(1, 20, 30)); rects.push_back(Rect(2, 30, 40)); rects.push_back(Rect(3, 25, 25)); rects.push_back(Rect(4, 15, 20)); rects.push_back(Rect(5, 10, 30)); rects.push_back(Rect(6, 10, 10)); rects.push_back(Rect(7, 40, 30)); vector<Rect> result = pack_rects(w - gap * 2, h - gap * 2, rects); for (int i = 0; i < result.size(); i++) { cout << "Rectangle " << result[i].id << " (" << result[i].w << ", " << result[i].h << ") at (" << result[i].x + gap << ", " << result[i].y + gap << ")" << endl; } return 0; } ``` 这个算法的实现思想是先按照面积大小对矩形进行排序,然后按照贪心策略依次将矩形装入最佳位置。装箱时,按照矩形高度和宽度的大小排序,并从大到小遍历已经排好的矩形,寻找可以放置当前矩形的最佳位置。 具体实现中,我们使用 `Bin` 类来表示一个装箱盒子,其中包含了当前盒子的宽度和高度,以及已经放置的矩形列表。对于每个 `Rect` 矩形,我们从已经放置的矩形中寻找可以放置它的最佳位置,并将它放置在这个位置上。如果找不到合适的位置,则说明当前盒子已经装不下这个矩形了。 最终,我们返回已经放置的矩形列表,这些矩形的坐标信息都已经被计算好了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值