最大子陣和
description
有乙個包含正數和負數的二維陣列。乙個子矩陣是指在該二維陣列裡,任意相鄰的下標是1*1或更大的子陣列。乙個子矩陣的和是指該子矩陣中所有元素的和。本題中,把具有最大和的子矩陣稱為最大子矩陣。
例如:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
這個陣列的最大子矩陣為:
9 2
-4 1
-1 8
其和為15。
input
輸入包含多組測試資料。每組輸入的第一行是乙個正整數n(1<=n<=100),表示二維方陣的大小。接下來n行每行輸入n個整數,表示陣列元素,範圍為[-127,127]。
output
輸出最大子陣和。
sample input 1
4sample output 10 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
15題解
這道題可以說是非常有意思了,看起來這道題是非常簡單的(當然實際上它也是簡單的),思路非常清晰明了。如果你和我一樣只是簡單地認為它就這麼簡單的話,那麼你現在的心情應當和我一樣。
基本思路【pa】:(可參考最大欄位和)
利用字首和的思路,先把它上下加起來,再把得到的新矩陣的左右加起來。
第一步可以得到:
0 -2 -7 0
9 0 -13 2
5 1 -17 3
4 9 -17 1
然後是第二步:
0 -2 -9 -9
9 9 -4 -2
5 6 -11 -8
4 13 -4 -3
這個時候,矩陣中的每個元素都代表的原矩陣中以對應元素為右下角的矩陣的和;
接下來我們就可以非常愉快地開始暴力解決問題。
遞推式:dp[ i ][ j ] = max(dp[ i ][ j ], sum[ i ][ j ] - sum[k - 1][ j ] - sum[ i ][l - 1] + sum[k - 1][l - 1])
sum陣列就是這個新矩陣。
打出**如下:
#includeusing namespace std;
int n;
int ma[147][147];
int sum[147][147];
int dp[147][147];
int main()
} for (int i = 1; i <= n; i++)
} for(int i = 1; i <= n; i++) }}
} int maxn = 0;
for (int i = 1; i <= n; i++)
} cout << maxn << endl;
} return 0;
}
然而很可惜的是這樣打出來的**並沒有順利地通過。為啥呢?它用了四重for,超時了。。。。
於是乎,我想了整整乙個下午,然後得到了一條優化思路:
只把原矩陣的上下加起來得到矩陣,然後再求最大子段和,不就可以求出最大子矩陣和了嗎?
於是我又花了乙個小時的時間把**打了出來:
#include#includeusing namespace std;
int n;
int m[147][147];
int sum[147][147];
int dp[147];
int main()
} memset(dp, 0, sizeof dp);
for (int i = 1; i <= n; i++)
memset(dp, 0, sizeof dp);
}} cout << maxn << endl;
} return 0;
}
是不是簡潔很多?
然後我就非常愉快地解決了。。
最大子陣和
解題思路 首先,考慮一維的情況。a1,a2,a3,an的最大子串行和。我們維護乙個 最大字首和 當這個字首和小於0的時候,就替換為當前值,那麼最大值一定在這些字首和中。然後對於二維的情況,我們列舉可能的起始列標,這樣就是一維的最大子串行和的問題了。例如,當我們選定第一列和第三列後,把每一行第一列到第...
藍橋杯 最大子陣 dp
歷屆試題 最大子陣 時間限制 1.0s 記憶體限制 256.0mb 問題描述 給定乙個n m的矩陣a,求a中的乙個非空子矩陣,使這個子矩陣中的元素和最大。其中,a的子矩陣指在a中行和列均連續的一塊。輸入格式 輸入的第一行包含兩個整數n,m,分別表示矩陣a的行數和列數。接下來n行,每行m個整數,表示矩...
最大子段(陣)和
這是一道dp經典題 感覺什麼都經典 也是很常見的乙個題型,具體思路就是用sum記錄乙個字首和,從a 1 遍歷到a n 每次,加上去,但是一旦sum成了負數,就沒必要字首和了,重新賦值0 因為前面就是累贅了 然後,就做出來了.1 include2 using namespace std 3int n,...