zoukankan      html  css  js  c++  java
  • 【HAOI2007】理想的正方形

    【问题描述】

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

    【输入】

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

    【输出】

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

    分析】

    单调队列,先处理横行,再处理竖行。

     1 #include <cstdlib>
     2 #include <iostream>
     3 #include <cmath>
     4 #include <cstdio>
     5 #include <cstring>
     6 const int MAX=1010;
     7 const int INF=0x7fffffff;
     8 using namespace std;
     9 //注意Max与Min(i,j)代表第i行从 
    10 int data[MAX][MAX],Max[MAX][MAX],Min[MAX][MAX];
    11 int a,b,n,ans=INF;
    12 
    13 void init();//输入数据
    14 void solve();
    15 void prepare(int hang);
    16 void work(int lie);
    17 
    18 int main()
    19 {
    20     //文件操作
    21     freopen("square.in","r",stdin);
    22     freopen("square.out","w",stdout);
    23     init();//输入数据 
    24     solve();//求解 
    25     return 0;
    26 }
    27 void init()
    28 {
    29     scanf("%d%d%d",&a,&b,&n);
    30     for (int i=1;i<=a;i++)
    31     for (int j=1;j<=b;j++) 
    32     scanf("%d",&data[i][j]);
    33 }
    34 void solve()
    35 {
    36      //计算出每行各个元素的最大值与最小值 
    37      for (int i=1;i<=a;i++) prepare(i);//横推行 
    38     // printf("
    ");
    39      for (int i=n;i<=b;i++) work(i);//纵推列 
    40      printf("%d
    ",ans);
    41 }
    42 void prepare(int hang)
    43 {
    44      int Q_MAX[MAX],front_MAX=1,rear_MAX=1;
    45      int Q_MIN[MAX],front_MIN=1,rear_MIN=1;
    46      for (int i=1;i<=n;i++)//预处理 
    47      {
    48          while (front_MAX<rear_MAX && data[hang][Q_MAX[rear_MAX]]<data[hang][i]) rear_MAX--;
    49          Q_MAX[++rear_MAX]=i;
    50          while (front_MIN<rear_MIN && data[hang][Q_MIN[rear_MIN]]>data[hang][i]) rear_MIN--;
    51          Q_MIN[++rear_MIN]=i;
    52      }
    53      //开始计算,千万要注意边界问题 
    54      for (int i=n;i<=b;i++)
    55      {
    56          //先计算MAX与MIN值 
    57          while (front_MAX<rear_MAX && Q_MAX[front_MAX+1]<(i-n+1)) front_MAX++; 
    58          Max[hang][i]=data[hang][Q_MAX[front_MAX+1]];
    59          while (front_MIN<rear_MIN && Q_MIN[front_MIN+1]<(i-n+1)) front_MIN++; 
    60          Min[hang][i]=data[hang][Q_MIN[front_MIN+1]];
    61          //再考虑加入队列 
    62          while (front_MAX<rear_MAX && data[hang][Q_MAX[rear_MAX]]<data[hang][i+1]) rear_MAX--;
    63          Q_MAX[++rear_MAX]=i+1;         
    64          while (front_MIN<rear_MIN && data[hang][Q_MIN[rear_MIN]]>data[hang][i+1]) rear_MIN--;
    65          Q_MIN[++rear_MIN]=i+1;
    66      }
    67      //打印
    68      //for (int i=n;i<=b;i++) printf("(%d %d) ",Max[hang][i],Min[hang][i]);
    69     // printf("
    "); 
    70 } 
    71 void work(int lie)
    72 {
    73      //printf("%d:",lie);
    74      int Q_MAX[MAX],front_MAX=1,rear_MAX=1;
    75      int Q_MIN[MAX],front_MIN=1,rear_MIN=1;
    76      for (int i=1;i<=n;i++)//预处理,注意这里换成行了 
    77      {
    78          while (front_MAX<rear_MAX && Max[Q_MAX[rear_MAX-1]][lie]<Max[i][lie]) rear_MAX--;
    79          Q_MAX[rear_MAX++]=i;
    80          while (front_MIN<rear_MIN && Min[Q_MIN[rear_MIN-1]][lie]>Min[i][lie]) rear_MIN--;
    81          Q_MIN[rear_MIN++]=i;
    82      }
    83      //开始计算,千万要注意边界问题 
    84      for (int i=n;i<=a;i++)
    85      {
    86          while (front_MAX<rear_MAX && Q_MAX[front_MAX]<(i-n+1)) front_MAX++; 
    87          while (front_MIN<rear_MIN && Q_MIN[front_MIN]<(i-n+1)) front_MIN++; 
    88          ans=min(ans,Max[Q_MAX[front_MAX]][lie]-Min[Q_MIN[front_MIN]][lie]);
    89          
    90          //printf("(%d %d) ",Q_MAX[front_MAX],Q_MIN[front_MIN]);
    91          //再考虑加入队列 
    92          while (front_MAX<rear_MAX && Max[Q_MAX[rear_MAX-1]][lie]<Max[i+1][lie]) rear_MAX--;
    93          Q_MAX[rear_MAX++]=i+1;         
    94          while (front_MIN<rear_MIN && Min[Q_MIN[rear_MIN-1]][lie]>Min[i+1][lie]) rear_MIN--;
    95          Q_MIN[rear_MIN++]=i+1;
    96      }
    97      //printf("
    ");
    98 }
    View Code
  • 相关阅读:
    How To Build CyanogenMod Android for smartphone
    CentOS安装Code::Blocks
    How to Dual boot Multiple ROMs on Your Android SmartPhone (Upto Five Roms)?
    Audacious——Linux音乐播放器
    How to Dual Boot Multiple ROMs on Your Android Phone
    Everything You Need to Know About Rooting Your Android Phone
    How to Flash a ROM to Your Android Phone
    什么是NANDroid,如何加载NANDroid备份?
    Have you considered compiled a batman-adv.ko for android?
    BATMAN—Better Approach To Mobile Adhoc Networking (B.A.T.M.A.N.)
  • 原文地址:https://www.cnblogs.com/hoskey/p/3746577.html
Copyright © 2011-2022 走看看