Singnal

体验RMQ

二维数组里找未知方阵的最大最小值之差。  

刚拿到这个题时感觉压力很大,因为虽然遍历扫描可以解决,但n^3的复杂度很大可能过不了,即使过了也丧失这道题的意义。于是用到了RMQ算法,强大的预处理,为什么呢:1,因为测试数据的数目不定,可能很大,如果只是简单的递归寻找,再寻找每一种情况时候必然会出现大量重复的过程,而这些过程没有被有效的记录下来供后面使用,使得效率不高;2,数据量庞大,我们不能一次扫描,于是在进行计算前对二维数组进行压缩,二叉树式压缩(我是这样看的,很不专业),RMQ最精妙之处就在于遍历到了树的所有末端,而又无任何重复的浪费。

即使思路清晰了,但实现上还是遇到很多问题,看来基本功还有待提升。以下代码,写得较冗长,见谅。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
short M[251][251][9];
short F[251][251][9];
inline short max4(int a,int b,int c,int d)
{
    int ma;
    if(max(a,b)>=max(c,d))ma=max(a,b);
    else ma=max(c,d);
    return ma;
}
inline short min4(int a,int b,int c,int d)
{
    int mi;
    if(min(a,b)<=min(c,d))mi=min(a,b);
    else mi=min(c,d);
    return mi;
}
int main()
{
    int N;
    int B;
    int K;
    int x;
    int y;

    scanf("%d%d%d",&N,&B,&K);
    for(int i=1; i<=N; i++)
        for(int j=1; j<=N; j++)
        {
            scanf("%d",&F[i][j][0]);
            M[i][j][0]=F[i][j][0];
        }

    for(int n=1; (1<<(n-1))<=B; n++)
        for(int i=1; i+(1<<n)-1<=N; i++)
            for(int j=1; j+(1<<n)-1<=N; j++)
            {
                F[i][j][n]=max4(F[i][j][n-1],
                                F[i+(1<<(n-1))][j][n-1],
                                F[i][j+(1<<(n-1))][n-1],
                                F[i+(1<<(n-1))][j+(1<<(n-1))][n-1]);
                M[i][j][n]=min4(M[i][j][n-1],
                                M[i+(1<<(n-1))][j][n-1],
                                M[i][j+(1<<(n-1))][n-1],
                                M[i+(1<<(n-1))][j+(1<<(n-1))][n-1]);

            }


    int KK=(int)(log2(B));
    for(int i=1; i<=K; i++)
    {
        scanf("%d%d",&x,&y);
        short max=max4(F[x][y][KK],
                       F[x+B-(1<<KK)][y][KK],
                       F[x][y+B-(1<<KK)][KK],
                       F[x+B-(1<<KK)][y+B-(1<<KK)][KK]);
        short min=min4(M[x][y][KK],
                       M[x+B-(1<<KK)][y][KK],
                       M[x][y+B-(1<<KK)][KK],
                       M[x+B-(1<<KK)][y+B-(1<<KK)][KK]);
        printf("%d\n",(max-min));
    }


    system("pause");
    return 0;
}

总结:1,大数组(特别是多维)应该在main以外定义,否则系统承受不了;
     2,发现将cin/cout改写为scanf/printf后速度提升相当大,直接从700ms降到188ms;

posted on 2011-06-25 04:44  Singnal  阅读(184)  评论(0编辑  收藏  举报