給定乙個n*m的矩陣a,求a中的乙個非空子矩陣,使這個子矩陣中的元素和最大。 其中,a的子矩陣指在a中行和列均連續的一塊。
輸入的第一行包含兩個整數n, m,分別表示矩陣a的行數和列數。(1 ≤ n, m ≤ 500)接下來n行,每行m個整數,表示矩陣a。
輸出一行,包含乙個整數,表示a中最大的子矩陣中的元素和。
3 3
-1 -4 3
3 4 -1
-5 -2 8
10
字首和+動態規劃
關鍵是如何把二維的子序和轉化為一維
leetcode 53.一維最大子序和解答
用乙個數sum
累加,如果sum>0
說明累加當前的數是會變大或變小的(可能是最優解的一部分),如果sum<0
那麼就讓sum
等於當前數(因為不可能是最優解,要重新開始),因為累加不肯能比單獨現在這個數大
方法:
這裡二維轉化成一維乙個重點就是一維子序和範圍可以理解成矩陣中的子矩陣
1 2 3
1 -1 -1 3
2 3 4 -1
3 -5 -2 8
我選擇第三列3,-1,8
作為乙個一維子序和時,可以得到結果10
,這也是乙個子矩陣,因為不管一維二維都是需要連續,二維連續就是子矩陣
範圍怎麼選定?答案是通過累加,我們不需要知道選的是**,只需要知道這一部分和就可以了,如這個例子的最優解是第二列加第三列,計算時只需要把第三列加到第二列,比較答案即可
把二維的子矩陣轉化為一維的列的最大子序和,通過列舉所有的列可能性得到答案,列中的所有可能一維子序和幫你列舉了
**實現:
資料從下標1開始存,初始化為0,這樣不用判斷範圍,也不用擔心會影響結果,範圍num[n][m]
列舉所有的列,需要兩個控制變數,乙個是開始範圍的i
也就是從第幾列開始i∈[
1,m]
i \in [1,m]
i∈[1,m
],然後是從i
開始的移動變數j
也就是從i
開始要幾列j∈[
i,m]
j\in[i,m]
j∈[i,m
],用乙個陣列dp
儲存第k
行的資料,然後累加第j
列,轉化為一維子序和求解,更新最大值
#include
#include
#include
using namespace std;
static
const
auto io_sync_off =
()()
;const
int maxn =
505;
int num[maxn]
[maxn]
;int dp[maxn]
;int
main()
ans =
max(mcur, ans);}
} cout << ans;
return0;
}
上述**沒有問題,但是求和的時候看著稍微有些累贅,並且要維護乙個dp
陣列,仔細想想是可以通過字首和得到某一列的值的,所以在輸入資料時將其維護成字首和陣列,這樣可以減少乙個迴圈(按說時間因該沒變化,但是更慢了wtf???)
要求某一塊列的和,那麼我們要對行累加(其實不是求列和,而是得到這一列到前面某一列範圍內的每行和,就是上乙個dp陣列,越說越亂,手動模擬一下就好了)
#include
#include
using namespace std;
static
const
auto io_sync_off =
()()
;const
int maxn =
505;
int dp[maxn]
[maxn]
;int
main()
int ans = dp[1]
[1];
for(
int i =
1; i <= m;
++i)
// 列舉列
for(
int j = i; j <= m;
++j)
// 要幾列
} cout << ans;
return0;
}
藍橋杯 最大乘積
演算法提高 最大乘積 時間限制 1.0s 記憶體限制 512.0mb 問題描述 對於n個數,從中取出m個數,如何取使得這m個數的乘積最大呢?輸入格式 第一行乙個數表示資料組數 每組輸入資料共2行 第1行給出總共的數字的個數n和要取的數的個數m,1 n m 15,第2行依次給出這n個數,其中每個數字的...
最大子矩陣 藍橋杯
問題描述 給定乙個n m的矩陣a,求a中的乙個非空子矩陣,使這個子矩陣中的元素和最大。其中,a的子矩陣指在a中行和列均連續的一塊。輸入格式 輸入的第一行包含兩個整數n,m,分別表示矩陣a的行數和列數。接下來n行,每行m個整數,表示矩陣a。輸出格式 輸出一行,包含乙個整數,表示a中最大的子矩陣中的元素...
藍橋杯 最大的算式
問題描述 題目很簡單,給出n個數字,不改變它們的相對位置,在中間加入k個乘號和n k 1個加號,括號隨便加 使最終結果盡量大。因為乘號和加號一共就是n 1個了,所以恰好每兩個相鄰數字之間都有乙個符號。例如 n 5,k 2,5個數字分別為1 2 3 4 5,可以加成 1 2 3 4 5 24 1 2 ...