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 }
  • 相关阅读:
    401. Binary Watch
    46. Permutations
    61. Rotate List
    142. Linked List Cycle II
    86. Partition List
    234. Palindrome Linked List
    19. Remove Nth Node From End of List
    141. Linked List Cycle
    524. Longest Word in Dictionary through Deleting
    android ListView详解
  • 原文地址:https://www.cnblogs.com/D-O-Time/p/7999880.html
Copyright © 2011-2022 走看看