提交 传送门: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
0 0 0
0 4 5
0 5 3
Sample Output
0 0 2
2 2 1
1 0 0
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;
}