procedure2012
It's not worth it to know you're not worth it!

[关键字]:搜索

[题目大意]:给出一个显示原矩阵每一个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;
}
posted on 2012-04-12 13:42  procedure2012  阅读(425)  评论(0)    收藏  举报