B1047 理想的正方形 RMQ

大家吸取我的教训,想好再写。我码了好长时间,最后发现算法处理的是另一个问题,我处理的是正方形情况的,才能用我优化之后的记忆化搜索,然而矩形就凉了。

先看一下题吧:

Description

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

  第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每
行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000
Output

  仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。
Sample Input
5 4 2

1 2 5 6

0 17 16 0

16 17 2 1

2 10 2 1

1 2 2 2
Sample Output
1
HINT

Source

我的反面教材代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
int a,b,n;
int p[1010][1010];
int f[1010][1010][15][3];
int l[15];
void dfs(int o,int x1,int y1,int x2,int y2)
{
    if(f[x1][y1][o][1] != -1)
        return;
    if(x1 == x2 && y1 == y2)
    {
        f[x1][y1][o][1] = p[x1][y1];
        f[x1][y1][o][0] = p[x1][y1];
        return;
    }
    int minn = INF;
    int maxn = 0;
    dfs(o + 1,x1,y1,x1 + l[o],y1 + l[o]);
    dfs(o + 1,a - l[o],y1,a,y1 + l[o]);
    dfs(o + 1,x1,b - l[o],x1 + l[o],b);
    dfs(o + 1,a - l[o],b - l[o],a,b); 
//    printf("%d %d %d %d
",a - l[o],b - l[o],a,b);
    maxn = max(maxn,f[x1][y1][o + 1][1]);
    minn = min(minn,f[x1][y1][o + 1][0]);
    maxn = max(maxn,f[a - l[o]][y1][o + 1][1]);
    minn = min(minn,f[a - l[o]][y1][o + 1][0]);
    maxn = max(maxn,f[x1][b - l[o]][o + 1][1]);
    minn = min(minn,f[x1][b - l[0]][o + 1][0]);
    maxn = max(maxn,f[a - l[o]][b - l[o]][o + 1][1]);
    minn = min(minn,f[a - l[o]][b - l[o]][o + 1][0]);
    f[x1][y1][o][1] = maxn;
    f[x1][y1][o][0] = minn;
    return;
}
int main()
{
    memset(f,-1,sizeof(f));
    read(a);read(b);read(n);
    duke(i,1,a)
    {
        duke(j,1,b)
            read(p[i][j]);
    }
    int k = n,len = 0;
    while(k > 1)
    {
        k = ceil(k / 2);
        l[++len] = k;
//        cout<<k<<endl; 
    }
    duke(i,1,a - n)
        duke(j,1,b - n)
            dfs(1,i,j,i + n,j + n);
    printf("%d %d
",f[1][1][1][1],f[1][1][1][0]);
    return 0;
}
/*
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
*/

然后就凉了,懒得写了,用二维的RMQ搞一下,抄了个比较清晰的代码。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int INF = 1000000000;
const int maxm = 1000 + 100;
const int maxn = 100 + 10;
const int maxlog = 10;

int a, b, n;
int logn;
int grid[maxm][maxm];
int maxv[maxm][maxm], minv[maxm][maxm];

int query (int x, int y)
{
    int _max = 0, _min = 0;
    _max = max(maxv[x][y], max(maxv[x+n-(1<<logn)][y+n-(1<<logn)], max(maxv[x+n-(1<<logn)][y], maxv[x][y+n-(1<<logn)])));
    _min = min(minv[x][y], min(minv[x+n-(1<<logn)][y+n-(1<<logn)], min(minv[x+n-(1<<logn)][y], minv[x][y+n-(1<<logn)])));
    return _max - _min;
}

int main ()
{
//    freopen("in.txt", "r", stdin);
    cin >> a >> b >> n;
    for (int i = 0; i < a; i++)
        for (int j = 0; j < b; j++)
        {
            scanf("%d", &grid[i][j]);
            maxv[i][j] = minv[i][j] = grid[i][j];
        }

    for (logn = 0; ((1<<(logn+1)) <= n); logn++);
    for (int k = 0; k < logn; k++)
        for (int i = 0; i+(1<<k) < a; i++)
            for (int j = 0; j+(1<<k) < b; j++)
            {
                maxv[i][j] = max(maxv[i][j], max(maxv[i+(1<<k)][j+(1<<k)], max(maxv[i+(1<<k)][j], maxv[i][j+(1<<k)])));
                minv[i][j] = min(minv[i][j], min(minv[i+(1<<k)][j+(1<<k)], min(minv[i+(1<<k)][j], minv[i][j+(1<<k)])));
            }

    int ans = INF;
    for (int i = 0; i <= a-n; i++)
        for (int j = 0; j <= b-n; j++)
            ans = min(ans, query(i, j));

    cout << ans;
    return 0;
}

唉,后悔啊。。。

原文地址:https://www.cnblogs.com/DukeLv/p/9515034.html