博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
luogu2216 [HAOI2007] 理想的正方形
阅读量:5040 次
发布时间:2019-06-12

本文共 3335 字,大约阅读时间需要 11 分钟。

题目大意

  有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

思路

  我们从暴力入手,每次枚举每一个正方形,然后在这个正方形里枚举每一个点,得到最大最小值。时间复杂度在枚举正方形内的点上增加了不少,如何优化?我们很容易想到单调队列。问题就在于怎么用。

  我自己有两个思路:一是当正方形在从左向右滑动时,对每一行建立单调队列跟随正方形一起滑动,要取整个正方形内的最值,在每一个单调队列的最值里取最值。但是枚举每一个单调队列的时间复杂度又上来了。怎么办?我的另外一个思路是整一个单调队列套单调队列。但这是自己发明的算法,不可尝试。

  我们看到我自己的思路都是想一边滑动正方形一边得结果。我们可以考虑把整个矩阵的结果统一处理出来最后扫描一遍整个矩阵得到结果。因此,我们可以先对每一排用单调队列处理出每个点向左长度为n的区域内的最值(队列中下标对应的值b是原矩阵中的值a),随后对每一列用单调队列处理出左上方n*n面积区域内的最值(队列中下标对应的值c是其对应的排上的最值b)。这样即可求解。

#include 
#include
#include
using namespace std;const int MAX_ROW = 1010, INF = 0x3f3f3f3f;int TotRow, TotCol, EdgeLen;int A[MAX_ROW][MAX_ROW];int RowMax[MAX_ROW][MAX_ROW], RecMax[MAX_ROW][MAX_ROW];int RowMin[MAX_ROW][MAX_ROW], RecMin[MAX_ROW][MAX_ROW];struct Window{private: struct Queue { private: int A[MAX_ROW]; int head, tail; public: void init() { head = tail = 0; } int back() { return A[tail - 1]; } int front() { return A[head]; } void pop_back() { tail--; } void push_back(int x) { A[tail++] = x; } void pop_front() { head++; } bool empty() { return head == tail; } }IdQ; int Tail, Len; int (*Id_Val) (int);//GetValById bool (*CmpVal) (int, int);//> or < public: void Init(int len, int (*id_val) (int), bool (*cmpVal) (int, int)) { IdQ.init(); Len = len; Tail = 0; Id_Val = id_val; CmpVal = cmpVal; } void Move() { Tail++; int head = Tail - Len + 1; while (head > 0 && !IdQ.empty() && IdQ.front() < head) IdQ.pop_front(); while (!IdQ.empty() && !CmpVal(Id_Val(IdQ.back()), Id_Val(Tail))) IdQ.pop_back(); IdQ.push_back(Tail); } int GetM() { return Id_Val(IdQ.front()); }}w1, w2;bool Gt(int a, int b) { return a >= b; }bool Lt(int a, int b) { return a <= b; }int CurRow;int GetColValInRow(int col) { return A[CurRow][col]; }void SlideRow(int row){ CurRow = row; w1.Init(EdgeLen, GetColValInRow, Gt); w2.Init(EdgeLen, GetColValInRow, Lt); for (int col = 1; col <= TotCol; col++) { w1.Move(); RowMax[row][col] = w1.GetM(); w2.Move(); RowMin[row][col] = w2.GetM(); }}int CurCol;int GetRowMaxInCol(int row) { return RowMax[row][CurCol]; }int GetRowMinInCol(int row) { return RowMin[row][CurCol]; }void SlideCol(int col){ CurCol = col; w1.Init(EdgeLen, GetRowMaxInCol, Gt); w2.Init(EdgeLen, GetRowMinInCol, Lt); for (int row = 1; row <= TotRow; row++) { w1.Move(); RecMax[row][col] = w1.GetM(); w2.Move(); RecMin[row][col] = w2.GetM(); }}int GetAns(){ int ans = INF; for (int row = EdgeLen; row <= TotRow; row++) for (int col = EdgeLen; col <= TotCol; col++) ans = min(ans, RecMax[row][col] - RecMin[row][col]); return ans;}int main(){ scanf("%d%d%d", &TotRow, &TotCol, &EdgeLen); for (int row = 1; row <= TotRow; row++) for (int col = 1; col <= TotCol; col++) scanf("%d", &A[row][col]); for (int row = 1; row <= TotRow; row++) SlideRow(row); for (int col = 1; col <= TotCol; col++) SlideCol(col); printf("%d\n", GetAns()); return 0;}

  

转载于:https://www.cnblogs.com/headboy2002/p/9439464.html

你可能感兴趣的文章
手把手教你写DI_1_DI框架有什么?
查看>>
.net常见的一些面试题
查看>>
OGRE 源码编译方法
查看>>
上周热点回顾(10.20-10.26)
查看>>
C#正则表达式引发的CPU跑高问题以及解决方法
查看>>
云计算之路-阿里云上:“黑色30秒”走了,“黑色1秒”来了,真相也许大白了...
查看>>
APScheduler调度器
查看>>
设计模式——原型模式
查看>>
【jQuery UI 1.8 The User Interface Library for jQuery】.学习笔记.1.CSS框架和其他功能
查看>>
如何一个pdf文件拆分为若干个pdf文件
查看>>
web.xml中listener、 filter、servlet 加载顺序及其详解
查看>>
前端chrome浏览器调试总结
查看>>
获取手机验证码修改
查看>>
数据库连接
查看>>
python中数据的变量和字符串的常用使用方法
查看>>
等价类划分进阶篇
查看>>
delphi.指针.PChar
查看>>
Objective - C基础: 第四天 - 10.SEL类型的基本认识
查看>>
java 字符串转json,json转对象等等...
查看>>
极客前端部分题目收集【索引】
查看>>