首页 > 代码库 > SPOJ MINSUB - Largest Submatrix(二分+单调栈)

SPOJ MINSUB - Largest Submatrix(二分+单调栈)

http://www.spoj.com/problems/MINSUB/en/

题意:给出一个n*m的矩阵M,和一个面积k,要使得M的子矩阵M‘的最小元素最大并且面积大于等于k,问子矩阵M‘的最小元素最大能是多少,并且求出最大的面积。

思路:二分一个最小元素x,转化为判断矩阵M里面是否存在一个子矩阵使得这个子矩阵的面积大于等于k并且所有元素都大于x。

用另一个矩阵,1表示该位置的元素大于等于x,0表示元素小于x。

转化为判断是否存在一个子矩阵元素为1的面积大于等于k。

这样可以用到早上学习的单调栈,去维护最大的子矩阵面积。

技术分享

像这样,求出最大的矩阵面积。

如果矩阵面积大于等于k,那么就去找是否有更大的x去满足题意。

 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 1010 4 struct node { 5     int pre, suf, val; 6 } p[N]; 7 int mat[N][N], mp[N][N], h[N][N], n, m, k, square; 8  9 bool check(int x) {10     memset(mp, 0, sizeof(mp));11     memset(h, 0, sizeof(h));12     for(int i = 1; i <= n; i++)13         for(int j = 1; j <= m; j++) if(mat[i][j] >= x) mp[i][j] = 1;14     square = 0;15     for(int i = 1; i <= n; i++) {16         stack<node> sta;17         for(int j = 1; j <= m; j++) {18             if(mp[i][j]) h[i][j] = h[i-1][j] + 1;19             p[j] = (node) {1, 1, h[i][j]};20         }21         sta.push(p[1]);22         for(int j = 2; j <= m; j++) {23             while(!sta.empty() && sta.top().val > p[j].val) {24                 node top = sta.top(); sta.pop();25                 if(!sta.empty()) sta.top().suf += top.suf;26                 p[j].pre += top.pre;27                 square = max(square, (top.suf + top.pre - 1) * top.val);28             }29             sta.push(p[j]);30         }31         while(!sta.empty()) {32             node top = sta.top(); sta.pop();33             if(!sta.empty()) sta.top().suf += top.suf;34             square = max(square, (top.suf + top.pre - 1) * top.val);35         }36     }37     if(square >= k) return true;38     return false;39 }40 41 void solve() {42     int t;43     scanf("%d", &t);44     while(t--) {45         scanf("%d%d%d", &n, &m, &k);46         int r = 0, l = 1000000000, ans;47         for(int i = 1; i <= n; i++) {48             for(int j = 1; j <= m; j++) {49                 scanf("%lld", &mat[i][j]);50                 if(mat[i][j] < l) l = mat[i][j];51                 if(mat[i][j] > r) r = mat[i][j];52             }53         }54         ans = l;55         while(l <= r) {56             int mid = (l + r) >> 1;57             if(check(mid)) l = mid + 1, ans = mid;58             else r = mid - 1;59         }60         check(ans);61         printf("%d %d\n", ans, square);62     }63 }64 65 int main() {66     solve();67     return 0;68 }

 

SPOJ MINSUB - Largest Submatrix(二分+单调栈)