問題描述ios
1002 二哥種花生算法
http://acm.sjtu.edu.cn/OnlineJudge/problem/1002
編程
二哥在本身的後花園裏種了一些花生,也快到了收穫的時候了。這片花生地是一個長度爲L、寬度爲W的矩形,每一個單位面積上花生產量都是獨立的。他想知道,對於某個指定的區域大小,在這麼大的矩形區域內,花生的產量最大會是多少。數組
第1行有2個整數,長度L和寬度W。學習
第2行至第L+1行,每行有W個整數,分別表示對應的單位面積上的花生產量A( \( 0 \leq A<10 \) )。測試
第L+2行有2個整數,分別是指定的區域大小的長度a和寬度b。spa
輸出一個整數m,表示在指定大小的區域內,花生最大產量爲m。code
4 5 1 2 3 4 5 6 7 8 0 0 0 9 2 2 3 3 0 0 0 1 3 3
38
左上角:38 = (1+2+3) + (6+7+8) + (0+9+2)orm
對於30%的數據: \( 1 \leq L,W \leq 100 \);ip
對於100%的數據: \( 1 \leq L,W \leq 1000 \)。
所有區域大小知足:\( 1 \leq a \leq L ,1 \leq b \leq W \) 。
個人第一次解決方案:
思路:
學習動態二維數組的建立
測試輸入輸出
算法實現
int L(0), W(0); //由輸入定義數組長度和寬度 cin >> L >> W; //百度到的方法,不知有沒有更好的方法? int **nut = new int*[L]; //分爲兩層定義 for (int i = 0; i < L; ++i) nut[i] = new int[W]; for (int i = 0; i < L; ++i){ for (int j = 0; j < W; ++j) cin >> nut[i][j]; }
由sample 覺得只要輸出左上角的那一塊的花生數量的和便可,提交後發現答案錯誤才明白應該是輸出全部可能的地塊中花生數量和最多的,因此應該要遍歷整個數組。可是這樣一來就有四重循環,十分不科學!
//定義動態二維數組 //@WuXueyang //1003 #include<iostream> using namespace std; int main() { int L(0), W(0); cin >> L >> W; //輸入花生地的長和寬 //定義數組 int **nut = new int*[L]; for (int i = 0; i < L; ++i) nut[i] = new int[W]; for (int i = 0; i < L; ++i){ for (int j = 0; j < W; ++j) cin >> nut[i][j]; } int l, w,result(0),temp(0); cin >> l >> w;//得到目標區塊的大小 //遍歷計算 for (int m =0; m < W-w+1; ++m){ for (int n = 0; n< L-l+1; ++n){ temp = 0; for (int i = n; i < n+l; ++i){ for (int j = m; j < m+w; ++j){ temp += nut[i][j]; } } if (result <= temp)result = temp; } } cout << result;//輸出結果 //釋放內存! for (int i = 0; i < L; ++i) delete[] nut[i]; delete[] nut; return 0; }
學習改進
就1002來講,它須要一個經常使用的技術——「前綴和」,儘管剛開始接觸編程可能不太熟悉。思路大體是這麼來的:你有沒有發如今枚舉的過程當中反覆計算了不少和?好比你在改變枚舉的axb的矩形左上角時,其實每向右移動一格,矩形內只有最左邊的一列被刪除並僅新增了最右的一列。這就提示咱們應該存在一種機制可以避免重複計算矩形內數的和。
具體作法是這樣的:咱們先考慮一維的情形,若是我事先計算出 pre[i] 表示前1-i個格子內數字之和,那麼完成這個處理以後,每次想要獲得任意一個區間 [l, r]的數字和,只須要計算 pre[r] - pre[l -1]便可。隨即咱們能夠推廣到二維,事先計算pre[i][j]表示以1, 1爲左上角,i, j爲右下角的矩形內數字之和。那麼不難推出若是要取得以x1, y1爲左上角 x2, y2爲右下角的矩形內數字之和,只需計算 pre[x2][y2] - pre[x1 - 1][y2] - pre[x2][y1 - 1] + pre[x1 - 1][y1 - 1] 便可(畫個圖就清楚了)。
改進版
//定義動態二維數組 //@WuXueyang //1003 #include<iostream> using namespace std; int main() { int L(0), W(0), t(0); cin >> L >> W; //輸入花生地的長和寬 //定義數組 int **store = new int*[L]; for (int i = 0; i < L; ++i) store[i] = new int[W]; for (int i = 0; i < L; ++i){ for (int j = 0; j < W; ++j){ cin >> t; if (j>0&&i>0)store[i][j] = store[i-1][j] + t + store[i][j-1] - store[i-1][j-1]; else if (j>0 && i == 0)store[i][j] = t + store[i][j-1]; else if (i > 0 && j == 0)store[i][j] = t + store[i - 1][j]; else store[i][j] = t; } } int l, w, result(0), temp(0); cin >> l >> w;//得到目標區塊的大小 //遍歷計算 for (int i = l - 1; i < L; ++i){ for (int j = w - 1; j < W; ++j){ if(i == l- 1 && j == w - 1)temp = store[i][j]; else if (i == l - 1 && j != w - 1)temp = store[i][j] - store[i][j - w]; else if (i != l - 1 && j == w - 1)temp = store[i][j] - store[i - l][j]; else temp = store[i][j] - store[i - l][j] - store[i][j-w] + store[i-l][j-w]; if (temp >= result)result = temp; } } cout << result;//輸出結果 //釋放內存! for (int i = 0; i < L; ++i) delete[] store[i]; delete[] store; return 0; }
時間: 1790ms 內存66056kb