题解/算法 {包含所有 1 的最小矩形面积 II}
@LINK: https://leetcode.cn/problems/find-the-minimum-area-to-cover-all-ones-ii/
;
虽然数据范围很小, 但没找到思路的话 还是很难的… 思维题
首先我们思考下两个的情况, 即网格空间里 有两个不会相互覆盖的矩形, 此时有一个性质: 你一定可以找到一个水平/垂直线 将整个空间切割为两部分 每个矩阵在每个部分里面;
| A A
A| _____
A|B B B B
|B B B B
这个性质 推广到三个的情况里 同样是适用的, 即网格空间里有三个不相互覆盖的矩阵, 你可以找到一个水平/垂直线 将整个空间切割为两个部分 然后每个部分 至少有1个矩阵;
C C C C C C|
_______ |A A B
A |A A B
A B B | B
B B |
这个性质 还是挺难想到的…
怎么证明呢? 你可以从两个的情况 推广过来, 即两个的情况时 此时你得到了一个切割线(垂直), 然后此时你再添加一个矩形: 如果这个矩阵和这个切割线冲突 那么其实可以发现 此时会存在一个水平的切割线;
假设这个切割线是水平的, 他可以划分成3种情况:
A A B|C
_____ _____ ______
B B|C A
___
C
如果切割线是垂直的 那么也是有3种情况 类似的(||, -|, |-
), 我们可以将垂直的情况 将矩阵转置一下 从而变成处理上面水平切割线的情况;
到了这里 就简单多了, 无非就是枚举这3种情况, 时间是30*30 * 30*30 = 1e6
;
int minimumSum(vector<vector<int>>& A) {
int ANS = 1e9;
auto Area = [&]( int _lx, int _ly, int _rx, int _ry)->int{
int N = A.size(), M = A.front().size();
if( _lx<0 || _lx>=N || _rx<0 || _rx>=N || _ly<0 || _ly>=M || _ry<0 || _ry>=M || _lx>_rx || _ly>_ry){ return -1;}
int Lx = 1e9, Rx = -Lx, Ly = Lx, Ry = Rx;
FOR_( i, _lx, _rx){
FOR_( j, _ly, _ry){
if( A[i][j] == 0){ continue;}
Lx = min( Lx, i); Rx = max( Rx, i);
Ly = min( Ly, j); Ry = max( Ry, j);
}
}
if( Lx == int(1e9)){ return -1;}
return (Rx-Lx+1) * (Ry-Ly+1);
};
auto Work = [&](){
int N = A.size(), M = A.front().size();
{
FOR_( r0, 0, N-1){
FOR_( r1, r0+1, N-1){
vector<int> res = {Area( 0, 0, r0, M-1), Area( r0+1, 0, r1, M-1), Area( r1+1, 0, N-1, M-1)};
if( std::count( res.begin(), res.end(), -1) != 0){ continue;}
ANS = min( ANS, std::accumulate( res.begin(), res.end(), 0));
}
}
}
{
FOR_( r, 0, N-1){
FOR_( c, 0, M-1){
vector<int> res = {Area( 0, 0, r, M-1), Area( r+1, 0, N-1, c), Area( r+1, c+1, N-1, M-1)};
if( std::count( res.begin(), res.end(), -1) != 0){ continue;}
ANS = min( ANS, std::accumulate( res.begin(), res.end(), 0));
}
}
}
{
FOR_( r, 0, N-1){
FOR_( c, 0, M-1){
vector<int> res = {Area( 0, 0, r, c), Area( 0, c+1, r, M-1), Area( r+1, 0, N-1, M-1)};
if( std::count( res.begin(), res.end(), -1) != 0){ continue;}
ANS = min( ANS, std::accumulate( res.begin(), res.end(), 0));
}
}
}
};
Work();
{ // inverse
vector temp( A.front().size(), vector<int>( A.size()));
FOR_( i, 0, A.size()-1){
FOR_( j, 0, A.front().size()-1){
temp[ j][ i] = A[i][j];
}
}
A = std::move( temp);
}
Work();
ASSERT_( ANS != (int)1e9);
return ANS;
}