1038: Not To The Max
Description
/* ----------------------------------------------------------------------------------
Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle.
As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
and has a sum of 15.
---------------------------------------------------------------------------------- */
Your task here has something similar with the problem mentioned above, while you are to find out a non-empty sub-matrix whose elements sum closest to the given integer T.
Input
The input contains several test cases.
Each test case begins with three integers n m T, which means there are n rows and m columns in the matrix and our target T as mentioned above. Then n lines follows, each of which consists of m non-negative integers bounded in [0, 10000].
You can assume that 0 < n <= 20, 0 < m <= 2000, 0 <= T < 2^15
You should process all test cases to the end of file.
Output
For each test case, you are to output a line in the from of "Case #:", # is the test case number indexed from 1, and then another line with the sum of the sub-matrix you found, if there is a tie, you should output the smaller one.
Sample Input
3 3 0
1 1 1
1 1 1
1 1 1
3 3 0
1 1 1
1 1 1
1 1 0
3 3 10
2 2 4
5 2 0
0 0 0
Sample Output
Case 1:
1
Case 2:
0
Case 3:
11
HINT
Source
#include<bits/stdc++.h>
#define INF 0x7fffffff
using namespace std;
int A[22][2010],F[22][2010],C[2010],dp[2010];
int N,M,T,kase;
void dfs(int L,int R,int &Min,int &ans){//二分求解
if(L==R){
if(abs(C[L]-T)<Min) Min=abs((C[L]-T)),ans=C[L];
else if(abs(C[L]-T)==Min && C[L]<ans) ans=C[L];
return;
}
dfs(L,(L+R)/2,Min,ans);dfs((L+R)/2+1,R,Min,ans);
int i=(L+R)/2,j=(L+R)/2+1;
int sum=C[i]+C[j];
while(i>=L || j<=R){//类似于归并排序的写法
if(abs(T-sum)<Min) Min=abs(T-sum),ans=sum;
else if(abs(T-sum)==Min && sum<ans) ans=sum;
if(sum>T) break;
if(j>R ||(i>=L && C[i]<C[j])) sum+=C[--i];
else sum+=C[++j];
}
}
void solve(){
int ans,Min=INF;
for(int i=1;i<=N;i++) for(int j=i;j<=N;j++){
for(int k=1;k<=M;k++) C[k]=F[j][k]-F[i-1][k];//转化为一维数组求解
dfs(1,M,Min,ans);//二分求一维数组的解
}
printf("Case %d:\n%d\n",kase,ans);
}
int main(){
//freopen("in.txt","r",stdin);
kase=1;
while(cin>>N>>M>>T){
for(int i=1;i<=N;i++) for(int j=1;j<=M;j++)
scanf("%d",A[i]+j);
for(int j=0;j<=M;j++) F[0][j]=0;//最大子矩阵的辅助数组
for(int j=1;j<=M;j++) for(int i=1;i<=N;i++)
F[i][j]=F[i-1][j]+A[i][j];
solve();kase++;
}
return 0;
}