zoukankan      html  css  js  c++  java
  • [HNOI2010] 矩阵 matrix

    标签:dfs+剪枝。

    题解:

      这道题看着就像一道dfs题目,没有什么算法可以用来算这个东西,于是想想暴搜。
      如果我们确定因为是2*2的子矩阵的和,如果确定了其中三个,那么就可以确定第四个,发现如果确定了第一行和第一列的话,就可以确定整个矩阵了,于是我们枚举只有399个了。
      因为要求字典序最小,我们先默认第一行和第一列全部是0,求出一个矩阵。我们先搜索第一行,从左到右。发现在(1,1)位置的数+k,那么在除了第一行和第一列的矩阵中,要合法,就要i+j为偶数的-=k,i+j为奇数的+=k即可。同样在(1,j)位置+=k,那么只影响这一列,便偶数行号-=k,奇数行号+=k即可。我们在保证了第一行最小的情况下,只要保证第一列最小即可满足字典序最小,因为确定第一行和第一列可以唯一的确定一个矩阵。
      第一行我们暴搜,当然需要剪枝了,对于每搜到第一行的一个数,就要扫一遍这一列,并且更新这一列的每个元素的所在行的行首的范围,也就是矩阵第一列每一个元素的范围,因为矩阵中的每一个元素只被三个数影响,那就是(1,1),以及行首与列首。更新了第一列每一个元素的范围之后,如果冲突即(L>R)那么就返回0。
      这里有一个技巧:按道理范围只要开一个O(n)的数组即可,但是这样需要备份,因为如过搜索失败了,那么回溯也要恢复范围数组的值,很麻烦,那么我们直接开一个二维数组,每次更新时取上一列的值与当前值比较之后再更新,这样就没有回溯的问题了,因为我们是从左到右枚举第一行的。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 using namespace std;
     5 const int MAXN=205,INF=0x3f3f3f3f;
     6 int n,m,P;
     7 int L[MAXN][MAXN],R[MAXN][MAXN],A[MAXN][MAXN];
     8 inline int gi(){int res; scanf("%d",&res); return res;}
     9 int F(int x){return (x&1)?1:-1;}
    10 int cal(int x,int y) { return A[x][y]+F(x+y)*A[1][1]+F(y)*L[x][m]+F(x)*A[1][y]; }
    11 bool dfs(int y)
    12 {
    13   if(y>m)return 1;
    14   int bacl[MAXN]={0},bacr[MAXN]={0};
    15   for(A[1][y]=0;A[1][y]<P;A[1][y]++)
    16     {
    17       bool flag=1;
    18       for(int i=2;i<=n;i++)
    19         {
    20           int tl=(A[i][y] + A[1][1]*F(i+y) + A[1][y]*F(i)) * F(y+1);
    21           int tr=(A[i][y] + A[1][1]*F(i+y) + A[1][y]*F(i)-(P-1)) * F(y+1);
    22           if(tl>tr)swap(tl,tr);
    23           L[i][y]=max(L[i][y-1],tl);
    24           R[i][y]=min(R[i][y-1],tr);
    25           if(L[i][y]>R[i][y])
    26             {flag=0; break;}
    27         }
    28       if(flag)
    29         if(dfs(y+1))
    30           return 1;
    31     }
    32   return 0;
    33 }
    34 int main()
    35 {
    36   n=gi(); m=gi(); P=gi();
    37   for(int i=1;i<=n;i++)
    38     {
    39       for(int j=1;j<=m;j++)
    40         {
    41           A[i][j]=gi();
    42           if(i!=1 && j!=1)
    43             A[i][j]-=(A[i][j-1]+A[i-1][j]+A[i-1][j-1]);
    44           R[i][j]=P-1;
    45         }
    46     }
    47   for(;A[1][1]<P;A[1][1]++)
    48     {
    49       if(dfs(2))
    50         {
    51           for(int i=1;i<=n;i++)
    52             for(int j=1;j<=m;j++)
    53               {
    54                 if(j==1 && i>1)
    55                   printf("%d ",L[i][m]);
    56                 else if(i==1 && j>1)
    57                   printf("%d%c",A[1][j],j==m?'
    ':' ');
    58                 else
    59                   printf("%d%c",cal(i,j),j==m?'
    ':' ');
    60               }
    61           return 0;
    62         }
    63     }
    64   return 0;
    65 }
  • 相关阅读:
    生成 n 位验证码的函数
    delphi的procedure of object
    delphi 文本 记录 流式 读写文件
    delphi save .dfm to .txt
    delphi xml
    delphi json
    delphi http server
    dac FDMemTable
    dac oracle
    dac mssql server
  • 原文地址:https://www.cnblogs.com/D-O-Time/p/7999880.html
Copyright © 2011-2022 走看看