[HNOI2012 Matrix]

[关键字]:搜索

[题目大意]:给出一个显示原矩阵每一个2*2得小正方形的和的矩阵,每个元素都小于p,求出一个字典序最小的原矩阵a满足所给矩阵。

//================================================================================

[分析]:如果能求出第一行和第一列就可以推算出所有的格子。首先假设第一行和第一列都是0然后可以得到一个不满足小于p的矩阵c,然后进行调整。如果在(1,1)加了a1,1那只要再将所有非第一行第一列的行列和为奇数的格子加上a1,1行列和是偶数的减去a1,1结果不会改变,如果在(1,j)加a1,j只要把这一列偶数行减奇数行加就能保证和不变,如果在(i,1)加上ai,1只要这一行奇数列加偶数列减。这样可以得到a1,1的公式a[i][j]=c[i][j]+sign(i+j+1)*a[1][1]+sign(i-1)*a[1][j]+sign(j-1)*a[i][1],sign(x)=-1x.只搜索(1,1)和第一行,然后根据0<=a[i][j]<p判断a[i][1]的取值范围如果下界大于上界就剪枝。

[代码]:

View Code
#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<cstring>

#include<algorithm>

using namespace std;



const int MAXN=300;



int a[MAXN][MAXN],c[MAXN][MAXN],s[MAXN][MAXN],l[MAXN][MAXN],r[MAXN][MAXN];

int n,m,p;



int sign(int n)

{

    return (n&1)?-1:1;

}



int Find(int i,int j)

{

    return c[i][j]+sign(i+j+1)*a[1][1]+sign(i-1)*a[1][j]+sign(j-1)*a[i][1];

}



bool DFS(int j)

{

     if (j>m) return 1;

     for (a[1][j]=0;a[1][j]<p;++a[1][j])

     {

         bool flag=1;

         for (int i=2;i<=n;++i)

         {

             int tl,tr;

             //tl=-(c[i][j]+sign(i+j+1)*a[1][1]+sign(i-1)*a[1][j])*sign(j-1);

             //tr=(p-1)-(c[i][j]+sign(i+j-1)*a[1][1]+sign(i-1)*a[1][j])*sign(j-1);

             tl=(c[i][j]+sign(i+j+1)*a[1][1]+sign(i-1)*a[1][j]-0)*(-1)*sign(j-1);

             tr=(c[i][j]+sign(i+j+1)*a[1][1]+sign(i-1)*a[1][j]-(p-1))*(-1)*sign(j-1);

             //printf("%d %d %d %d\n",tl,tr,i,j);

             if (tl>tr) swap(tl,tr);

             l[i][j]=max(l[i][j-1],tl);

             r[i][j]=min(r[i][j-1],tr);

             if (l[i][j]>r[i][j]) {flag=0;break;}

         }

         if (flag)

            if (DFS(j+1)) return 1;

     }

     return 0;

}



int main()

{

    freopen("in.txt","r",stdin);

    freopen("out.txt","w",stdout);

    scanf("%d%d%d",&n,&m,&p);

    for (int i=1;i<=n;++i)

        for (int j=1;j<=m;++j)

        {

            scanf("%d",&s[i][j]);

            l[i][j]=0;

            r[i][j]=p-1;

            if (i!=1 && j!=1) c[i][j]=s[i][j]-c[i-1][j]-c[i][j-1]-c[i-1][j-1];

        }

    for (a[1][1]=0;a[1][1]<p;++a[1][1])

        if (DFS(2))

        {

                   for (int i=2;i<=n;++i) a[i][1]=l[i][m];

                   for (int i=1;i<=n;++i)

                   {

                       for (int j=1;j<=m;++j)

                           printf("%d ",Find(i,j));

                       printf("\n");

                   }

                   break;

        }

    fclose(stdin);

    fclose(stdout);

    return 0;

}

你可能感兴趣的:(Matrix)