[Hnoi2010]Matrix 矩阵解题报告及AC代码

提交 传送门:http://www.zybbs.org/JudgeOnline/problem.php?id=2003

Description

Input

第一行包含三个正整数N M P表示矩阵的行数列数以及每个数的范围,接下来N行每行包含M个非负整数,其中第i行第j个数表示以格子(i,j)为右下角的2*2子矩阵中的数的和。保证第一行与第一列的数均为0,且每个和都不超过4(P-1)。

Output

包含N行,每行M个整数,描述你求出的矩阵,相邻的整数用空格分开。(行末不要有多余空格)

Sample Input

3 3 3
0 0 0
0 4 5
0 5 3

Sample Output

0 0 2
2 2 1
1 0 0

HINT

30% N,M<=10
另外30% P=2
100% 1<N,M<=200,1<P<=10

 
解题报告:
    搜索+剪枝优化
 
AC Code:
/************************************************************** 
    Problem: 2003 
    Language: C++ 
    Result: Accepted 
****************************************************************/
  
#include<stdio.h> 
const int N=222; 
int s[N][N],c[N][N],a[N][N],n,m,p,l[N][N],r[N][N]; 
inline int sign(int a){return a&1?-1:1;} 
inline int num(int i,int j){return c[i][j]+a[0][0]*sign(i+j+1)+a[0][j]*sign(i)+a[i][0]*sign(j);} 
inline void swap(int &a,int &b){int t=a;a=b;b=t;} 
inline int max(int a,int b){return a>b?a:b;} 
inline int min(int a,int b){return a<b?a:b;} 
bool dfs(int j){ 
    if(j==m)return true; 
    for(a[0][j]=0;a[0][j]<p;++a[0][j]){ 
        bool ok=true; 
        for(int i=1;i<n;++i){ 
            int tl,tr; 
            tl=(c[i][j]+a[0][0]*sign(i+j+1)+a[0][j]*sign(i)-0)*(-1)*sign(j); 
            tr=(c[i][j]+a[0][0]*sign(i+j+1)+a[0][j]*sign(i)-(p-1))*(-1)*sign(j); 
            if(tl>tr)swap(tl,tr); 
            l[j][i]=max(l[j-1][i],tl); 
            r[j][i]=min(r[j-1][i],tr); 
            if(l[j][i]>r[j][i]){ok=false;break;} 
        } 
        if(ok)if(dfs(j+1))return true; 
    } 
    return false; 
} 
int main(){ 
    scanf("%d%d%d",&n,&m,&p); 
    for(int i=0;i<n;++i) 
      for(int j=0;j<m;++j){ 
        scanf("%d",&s[i][j]); 
        if(i&&j)c[i][j]=s[i][j]-c[i-1][j]-c[i][j-1]-c[i-1][j-1]; 
        l[j][i]=0;r[j][i]=p-1; 
      } 
    for(a[0][0]=0;a[0][0]<p;++a[0][0]) 
      if(dfs(1)){ 
        for(int i=1;i<n;i++)a[i][0]=l[m-1][i]; 
        for(int i=0;i<n;++i) 
          for(int j=0;j<m;++j) 
            printf("%d%s",num(i,j),j+1==m?"\n":" "); 
          break; 
      } 
    return 0; 
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值