2019牛客暑期多校(第二场) H题 悬线法or单调栈

登录—专业IT笔试面试备考平台_牛客网

https://ac.nowcoder.com/acm/contest/882/H

Second Large Rectangle

悬线法用来求解最大子矩形问题

通过悬线法,可以找到以点(i,j)为底的极大矩形。

u[i][j]、l[i][j]、r[i][j]分别表示以为底的极大矩形的上边界,左边界,右边界;

首先预处理:找到点(i,j)可以沿伸的的上端点、左端点,右端点 (dp)

For i = 1 to n
    For j = 1 to m
        u[i][j] = (i-1,j)==1 ? u[i-1][j] : i;
        l[i][j] = (i,j-1)==1 ? l[i][j-1] : j;
    For j = m to 1
        r[i][j] = (i,j+1)==1 ? r[i][j+1] : j;

如图找到了(4,3)  的   上端点、左端点,右端点,但是这些边界并没有组成一个矩形,可以(4,3)的上端点为上边界,找到左右边界,这样就可以找到一个以点(4,3)为底、以点(4,3)上界为高的极大矩形。

For i = 1 to n
    For j = 1 to m
        if (i-1,j)==1
            l[i][j] = max(l[i][j], l[i-1][j]
            r[i][j] = min(r[i][j], r[i-1][j]
矩形面积就是 (r[i][j] − l[i][j] + 1) ∗ (i − u[i][j] + 1)
代码:
#include<bits/stdc++.h>
using namespace std;

const int N = 1e3+100;

int n, m;
int g[N][N];
int u[N][N];
int l[N][N];
int r[N][N];
int hh,ll,rr,bb;
char str[N];
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++){
        scanf("%s",str+1);
        for(int j =1;j<=m;j++ ){
            if(str[j] == '1') g[i][j] = 1;
            else g[i][j] = 0;
        }
    }
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            u[i][j] = l[i][j] = r[i][j] = 0;
    
    
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if(g[i][j] == 0)    continue;
                u[i][j] = g[i-1][j] == 1 ? u[i-1][j] : i;
                l[i][j] = g[i][j-1] == 1 ? l[i][j-1] : j;
        }
        for(int j = m; j >= 1; j--){
            if(g[i][j] == 0)    continue;
            r[i][j] = g[i][j+1] == 1 ? r[i][j+1] : j;
        }
    }
    int ans = 0;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if(g[i][j] == 0)    continue;
            if(g[i-1][j] == 1){
                l[i][j] = max(l[i][j], l[i-1][j]);
                r[i][j] = min(r[i][j], r[i-1][j]);
            }
            if(ans<(r[i][j]-l[i][j]+1)*(i-u[i][j]+1)){
                hh = u[i][j] , bb =i;
                rr = r[i][j],ll=l[i][j];
                ans = (r[i][j]-l[i][j]+1)*(i-u[i][j]+1);
            }
        }
    }
    int ans2 = 0;
    ans2= max(ans2,(rr - ll) * (bb - hh + 1));
    ans2= max(ans2,(rr - ll +1) * (bb - hh ));
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if(g[i][j] == 0)    continue;
            if(hh==u[i][j]&&bb==i&&ll==l[i][j]&&rr==r[i][j])
                continue;
            if(ans2<(r[i][j]-l[i][j]+1)*(i-u[i][j]+1)){
                ans2=(r[i][j]-l[i][j]+1)*(i-u[i][j]+1);
            }
        }
    }
    cout << ans2 << endl;
    return 0;
}
单调栈解法:
	

h[i][j] 表示,点(i,j)到上界的高度,

对于行 i ,通过单调栈对点(i,j)的高度进行处理,可以得到该高度可以形成矩形的左右边界 l[i][j] , r[i][j] ;

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+100;
int n, m;
char str[N][N];
int h[N][N];
int l[N][N],r[N][N];
stack<int> s;
int hh,bb,rr,ll;
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++){
        scanf("%s", str[i]+1);
    }
    int ans = 0;
    for(int i = 1;i <= n; i++){
        for(int j = 1;j <= m; j++){
            if(str[i][j] == '1')
                h[i][j] = h[i-1][j] + 1;
            else
                h[i][j] = 0;
        }
        
        for(int j = 1;j <= m; j++){
            while(!s.empty() && h[i][j]<h[i][s.top()]){
                r[i][s.top()] = j; s.pop();
            }
            if(!s.empty()){
                if(h[i][j]==h[i][s.top()]) 
                    l[i][j] = l[i][s.top()];
                else l[i][j] = s.top();
            }
            else l[i][j] = 0;
            s.push(j);
        }
        while(!s.empty()){
            r[i][s.top()] = m+1; s.pop();
        }
        for(int j = 1;j <= m; j++){
            if(ans < h[i][j]*(r[i][j]-l[i][j]-1)){
                hh=h[i][j], bb=i, rr=r[i][j], ll=l[i][j];
                ans = h[i][j]*(r[i][j]-l[i][j]-1);
            }
        }
    }
    int ans2 = 0;
    ans2=max(ans2,hh*(rr-ll-2));
    ans2=max(ans2,(hh-1)*(rr-ll-1));
    for(int i = 1;i <= n; i++){
        for(int j = 1;j <= m; j++){
            if(hh==h[i][j]&&bb==i&&rr==r[i][j]&&ll==l[i][j])
                continue;
            ans2 = max(ans2,h[i][j]*(r[i][j]-l[i][j]-1));
        }
    }
    cout << ans2 << endl;
    return 0;
}


全部评论
请问 你这两句为什么要加上?    ans2=max(ans2,hh*(rr-ll-2));    ans2=max(ans2,(hh-1)*(rr-ll-1));
点赞 回复 分享
发布于 2019-07-26 09:18

相关推荐

美团开奖了,谁说测开比后端薪资低?谁说前端比后端薪资低?好了你又要说后端可以争取sp、ssp,但是能拿到美团白菜offer的就已经算是人中龙凤了,拿到sp、ssp更是凤毛麟角!依旧劝退后端!你后端学历内卷炼狱!实习经历卷的爆!甚至无法入行!入行了也只是和测开、前端的一般!1.学历,最痛的一击!后端工程师的第一步,走得不是技术,而是学历!想要进入大厂?好好看清楚自己的身份证:没有名校背景,别想着进美团、字节、腾讯!&nbsp;面试官看你的第一眼就会想:“呵,去,给你点面试机会,看看你的技术!”什么?你说自己有技术?不好意思,来点GitHub链接,Project经历,能让面试官笑着赶你走。你没个985、211,双一流,根本就无法站稳在这场技术竞赛的起点。你想进大厂,没学历,没技术!永远只有一个词——&nbsp;“被无情拒绝”。2.&nbsp;薪资:你不过是和前端、测开的一匹马“后端工程师薪资高?能进SSP就是牛逼!”SSP?&nbsp;听起来像是你梦想的银河,但实际上能拿到这个级别的人&nbsp;凤毛麟角,除非你在面试官面前像神话人物一样打了个响指,否则你连SSP的尾巴都摸不着。至于你说的“前端薪资不高”?别逗了,前端都在笑你呢,&nbsp;他们搞个页面,工资比你写个亿级请求接口还多。你说你辛辛苦苦优化API、调度缓存,别人搞个UI设计就能多拿几千块。前端已经不止是个展示层了,他们赚得比你还轻松,而你不过是服务器上疯狂跑“CRUD操作”的那只笨重的工蚁。3.&nbsp;后端的真正意义:修&nbsp;Bug,解决问题,下一份工作还是修&nbsp;Bug有多少人觉得后端是系统架构、数据库优化的高端战场?醒醒吧!&nbsp;后端的真正使命:维护旧项目,修复别人留下的烂摊子。你觉得自己能构建一个完美的系统?不!你只会一边修复技术债务,一边打着&nbsp;“重构”&nbsp;的旗号,换来的是&nbsp;“重构再重构”&nbsp;的无尽循环。而且,别告诉我你能专心写代码。你又要写代码,又要看服务器日志,没事还得帮别人&nbsp;修崩的数据库,给前端数据源做“格式化”。你就是那块永远处于消耗型工作的&nbsp;“万金油”。4.&nbsp;晋升?哈哈哈,你是在做梦!你以为后端开发是一条顺风顺水的快速晋升路线?错!&nbsp;你永远只能在一个“程序员”的岗位上打转,或者你为自己设立目标:“我要成为架构师”,那真的是在妄想。架构师?高级开发?靠近那条道路,你的心脏会先被晋升难度给捏住,你前方只有一座座高不可攀的技术山。别看那些SSP,架构师,架构啥呀?公司里的架构都是前端架构师,你就坐在后端的角落里,照顾着你那些满是错误的API和服务器。5.&nbsp;加班?还是加班!你以为后端开发能像文艺片那样“偶尔加个班”?哈哈,傻了吧!&nbsp;后端开发的生活是无休止的加班和修bug,你不仅要写接口,还得守夜调度、监控系统性能。就连你写的那个“完美的数据库查询”,也可能在&nbsp;第二天&nbsp;被前端因为“页面卡顿”给打回原形。“没有加班,你还能吃什么饭?”你说你是程序员,结果你的生活全是&nbsp;熬夜加班、调试、重启。前端跑个页面,喝个咖啡就能过关,而你呢,熬夜跟数据库调试,最后还是那个穷忙的死循环。6.&nbsp;技术天花板:架构?技术深度?笑死了!后端开发的天花板?那不过是个永远也摸不着的架构师“梦想”,你能掌握几款框架、几种数据库、两三套微服务架构,最后也不过是个&nbsp;管理端的“搬运工”。你没办法“打破天花板”,更没有机会跳出“自己写个爬虫”或者“API接口”的死循环。技术深度?你也不过是&nbsp;“技术债务”的修复者,一天到晚都在修补“老旧系统”的缺陷,偶尔听前端同学聊聊他们React、Vue的最新版本,你根本无法理解他们说的是什么。
开心小狗🐶:感觉后端有点像考研的0812,报名的时候都想冲0812,看不上0854。但是真入学了,不都是众生平等
点赞 评论 收藏
分享
想玩飞盘的菠萝蜜在春...:上交✌🏻也拒?
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务