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 }
  • 相关阅读:
    learnyou 相关网站
    hdu 3038 How Many Answers Are Wrong
    hdu 3047 Zjnu Stadium 并查集高级应用
    poj 1703 Find them, Catch them
    poj 1182 食物链 (带关系的并查集)
    hdu 1233 还是畅通工程
    hdu 1325 Is It A Tree?
    hdu 1856 More is better
    hdu 1272 小希的迷宫
    POJ – 2524 Ubiquitous Religions
  • 原文地址:https://www.cnblogs.com/D-O-Time/p/7999880.html
Copyright © 2011-2022 走看看