【上海交大OJ】二哥种花生
http://acm.sjtu.edu.cn/OnlineJudge/problem/1002
Description
二哥在自己的后花园里种了一些花生,也快到了收获的时候了。这片花生地是一个长度为L、宽度为W的矩形,每个单位面积上花生产量都是独立的。他想知道,对于某个指定的区域大小,在这么大的矩形区域内,花生的产量最大会是多少。
Input Format
第1行有2个整数,长度L和宽度W。
第2行至第L+1行,每行有W个整数,分别表示对应的单位面积上的花生产量A( 0≤A<10 )。
第L+2行有2个整数,分别是指定的区域大小的长度a和宽度b。
Output Format
输出一个整数m,表示在指定大小的区域内,花生最大产量为m。
Sample Input
4 5
1 2 3 4 5
6 7 8 0 0
0 9 2 2 3
3 0 0 0 1
3 3
Sample Output
38
样例解释
左上角:38 = (1+2+3) + (6+7+8) + (0+9+2)
数据范围
对于30%的数据: 1≤L,W≤100;
对于100%的数据: 1≤L,W≤1000。
全部区域大小满足:1≤a≤L,1≤b≤W 。
问题分析:
这个题目看上去还是挺容易的,至少不会完全没有思路,一般来说最简单也最直观的思路就是对长度为L,宽度为W的矩阵进行遍历,计算每个长度为a,宽度为b的小矩阵中元素之和。
for(unsigned int i = 0; i < all_length - avai_length + 1; i++){ for(unsigned int j = 0; j < all_width - avai_width + 1; j++){ for(unsigned int k = i; k < i + avai_length; k++){ for(unsigned int z = j; z < j + avai_width; z++){ max_tmp += avai_num[k][z]; } } if(max_tmp > max_last) { max_last = max_tmp; } max_tmp = 0; } } cout<<max_last<<" ";
四重循环,算法要进行的加法次数 ab(L-a+1)(W-b+1)
这是一个正确的算法,但却不是一个好算法,提交后有几组提示超过时间限制。
其实有些计算是可以避免的,比如我们在计算小矩阵中左上角元素为a[i][j]值的时候,只要计算(a[i][j+b-1]-a[i][j-1]+……+a[i+a-1][[j+b-1]+a[i+a-1][j-1]) ,然后将上次计算的矩阵和加上这个差值就好。
当每次横向移动时,我们需要保存每个横行的最大值,因为在换行时上面的方法是不适用的。
假如横向移动,加法次数 ab+b(L-a+1)+a(W-b+1)(L-a+1)
忽略前面两个低次项运算次数,主要影响因素是a(W-b+1)(L-a+1)
同样,如果竖向移动,主要影响因素是b(W-b+1)(L-a+1)
所以算法判断一下a和b的大小决定移动的方向,获得最少的运算次数。
#include <iostream> using namespace std; int main() { unsigned int all_length, all_width; unsigned int avai_length, avai_width; unsigned int * max; unsigned int max_last=0, max_now, max_diff = 0, max_last_final = 0; unsigned int **avai_num = NULL; cin>>all_length>>all_width; avai_num = new unsigned int* [all_length]; for(unsigned int i = 0; i < all_length; i++) { avai_num[i] = new unsigned int[all_width]; } for(unsigned int i = 0; i < all_length; i++){ for(unsigned int j = 0; j < all_width; j++){ cin>>avai_num[i][j]; } } cin>>avai_length>>avai_width; if(avai_width >= all_length){ max = new unsigned int [all_length - avai_length + 1]; for(unsigned int i = 0; i < all_length - avai_length + 1; i++){ max[i] = 0; } for(unsigned int i = 0; i < avai_length; i++){ for(unsigned int j = 0; j < avai_width; j++) max[0] += avai_num[i][j]; } for(unsigned int i = 1; i < all_length - avai_length + 1; i++){ for(unsigned int j = 0; j < avai_width; j++){ max_diff += avai_num[i+avai_length-1][j] - avai_num[i-1][j]; } max[i]= max[i-1]+max_diff; max_diff = 0; } max_diff=0; for(unsigned int i = 0; i < all_length -avai_length + 1; i++){ max_last_final = max[i]; for(unsigned int j = 1; j < all_width -avai_width + 1; j++){ for(unsigned int k = 0; k < avai_length; k++){ max_diff += avai_num[i+k][j+avai_width-1] - avai_num[i+k][j-1]; } max_now = max_last_final + max_diff; max_last_final = max_now; if(max_now > max[i]) max[i] = max_now; max_diff = 0; } } for(unsigned int i = 0; i < all_length - avai_length + 1; i++){ if(max_last_final < max[i]) max_last_final = max[i]; } cout<<max_last_final; } else{ max = new unsigned int [all_width - avai_width + 1]; for(unsigned int i = 0; i < all_width - avai_width + 1; i++){ max[i] = 0; } for(unsigned int i = 0; i < avai_length; i++){ for(unsigned int j = 0; j < avai_width; j++) max[0] += avai_num[i][j]; } for(unsigned int i = 1; i < all_width - avai_width + 1; i++){ for(unsigned int j = 0; j < avai_length; j++){ max_diff += avai_num[j][i+avai_width-1] - avai_num[j][i-1]; } max[i]= max[i-1]+max_diff; max_diff = 0; } max_diff=0; for(unsigned int i = 0; i < all_width -avai_width + 1; i++){ max_last_final = max[i]; for(unsigned int j = 1; j < all_length -avai_length + 1; j++){ for(unsigned int k = 0; k < avai_width; k++){ max_diff += avai_num[j+avai_length-1][i+k] - avai_num[j-1][i+k]; } max_now = max_last_final + max_diff; max_last_final = max_now; if(max_now > max[i]) max[i] = max_now; max_diff = 0; } } for(unsigned int i = 0; i < all_width - avai_width + 1; i++){ if(max_last_final < max[i]) max_last_final = max[i]; } cout<<max_last_final; } for(unsigned int i = 0; i < all_length; i++) { delete [] avai_num[i]; } delete [] avai_num; delete [] max; return 0; }