题目链接🔗:2032. 过度种植 - AcWing题库
分析:
考验思维的好题
首先这道题如果逐一矩阵去枚举的话,肯定是会超时的因为时间复杂度达到了近O(n^3)
因此这种方法行不通 所谓正难则反 我们为何不用总的面积减去重叠的面积呢?顺着这条思路
我们想到了容斥原理
容斥原理:三个集合的容斥关系公式:A∪B∪C = A+B+C - A∩B - B∩C - C∩A +A∩B∩C
推广到N维通式:即当一个集合项中包含偶数项时(如上式的 A∩B)则前面符号为符号,反之为奇数项时,前置符号为正
因此 我们需要做的就是 枚举每一种重叠矩形可能出现的情景
通俗来讲 对于任意一个重叠矩形 原N个矩形中每个矩形都有两种状态 即重叠矩形的出现是有它参与的或者没有 即选或不选 因此我们想到了用二进制做优化来表示每个矩形选或者不选
还有一点需要注意 :
在每次枚举重叠矩形时 我们要找的是所有有重叠矩形的交集 即最小值 因此 下端点 (x1,y1) 应取max 上端点 (x2,y2) 应取min 这里请仔细思考清楚!
剩下的就请看代码的注释啦~
rect = [] # 储存矩形的左下角和右上角的坐标
res = 0
INF = float('inf')
N = int(input())
for i in range(N) :
a,b,c,d = map(int,input().split())
rect.append((a,d,c,b)) # 这里b和d换下位置记录,这样就能记录矩形的左下角和右上角的坐标了
def get(state) :
x1,y1,x2,y2 = -INF,-INF,INF,INF
cnt = 0 # 记录本次一共有几个矩形参与构造重叠矩形 => 判断前置符号
area = 0
for i in range(N) :
if state >> i & 1 : # 逐位判断 如果第i个矩形是被选中
cnt += 1
x1 = max(x1,rect[i][0])
y1 = max(y1,rect[i][1])
y2 = min(y2,rect[i][3])
area = max(0,x2-x1) * max(0,y2-y1) # 这里要注意:由于有可能这种情况下 并没有产生重叠矩形 所以要和0取max
if cnt % 2 == 0 : return -area # 如果有偶数个矩形被选中 => 前置符号为负号
return area
for i in range(1,1<<N) : # 因为只有N个矩形,所以只需要枚举1~2^N-1这N个状态 (1<<N) = 1 * 2^N
res += get(i)
print(res)