問題描述:
給定乙個非負陣列arr,和乙個正數m。所有子串行的和模上m的值全部求出來,求出最大的即可。返回arr的所有子串行中累加和 %m 之後的最大值。
如果arr中每個數字不大,怎麼做?
如果arr中 m 的值很小,怎麼做?
如果arr的長度很短,但是arr每個數字比較大並且m比較大呢?
code:
/** 生成每個子串行和的遞迴函式
* @param arr: 原始陣列名
* @param n: 原始陣列長度
* @param aux_arr: 輔助陣列名,每次求得的子串行和的值放在輔助陣列裡面
* @param index: 等價於二叉樹的層數
* @param k: aux_arr陣列的遍歷位置
* @param sum: 記錄的和
*/int
process
(int
* arr,
int* aux_arr,
int index,
long
& k,
int sum,
int n)
else
}/** 暴力解法 分治問題
* @param arr: 陣列名
* @param n: 陣列長度 n 不能太大,2^32 就已經是uint的極限了
* @param m: 模數
*/int
solution1
(int
* arr,
int n,
int m)
delete
aux_arr;
return maxvalue;
}
這是乙個類揹包問題,dp型別是從左往右的(一共有四種型別)。
同時,這裡有三小問,每一小問的引數取值不同,所以肯定需要採用不同的解法,這就是所謂的看菜吃飯。
1)如果arr中每個數字不大,怎麼做?
arr中每個數字不大,那麼陣列和sum就不大,二維dp表可以如下建法:
/** 動態規劃解法(二維dp) 對應第一小問:arr中每個數字不大的情況
* @param arr: 陣列名
* @param n: 陣列長度
* @param m: 模數
*/int
solution2
(int
* arr,
int n,
int m)
// initialize
for(
int i =
0; i < n;
++i)
}for
(int i =
0; i < n;
++i)
dp[0]
[arr[0]
]=true
;for
(int i =
1; i < n;
++i)}}
int ans =0;
// 最後遍歷最後一行就好了
for(
int i =
0; i <= sum;
++i)
// free memory
for(
int i =
0; i < n;
++i)
delete
dp;return ans;
}2)如果arr的sum比較大,而arr中 m 的值很小,怎麼做?
也是建個二維dp表,但是是以m來建, dp[n][m]。
code:
/** 動態規劃解法(二維dp) 對應第二小問:arr中每個數字比較大,而 m 比較小的情況
* @param arr: 陣列名
* @param n: 陣列長度
* @param m: 模數
*/int
solution3
(int
* arr,
int n,
int m)
// initialize
for(
int i =
0; i < n;
++i)
}for
(int i =
0; i < n;
++i)
dp[0]
[arr[0]
% m]
=true
;for
(int i =
1; i < n;
++i)
else}}
int ans =0;
// 最後遍歷最後一行就好了
for(
int i =
0; i < m;
++i)
// free memory
for(
int i =
0; i < n;
++i)
delete
dp;return ans;
}
2)如果arr的sum和m都比較大,而arr的長度比較小,怎麼做?
所以針對上面圖示具體要求,對整個陣列暴力肯定超時,那麼可以將陣列分半,分別去求mod完後的值,然後合併。
具體見code:
// 在arr[index, end]上自由選擇,每一種選擇出來的累加和 mod m 的結果
// 放到set中去
void
process
(int
* arr,
int index,
int sum,
int end,
int m, std::set<
int>
& s)
}/** 第三小問,如果arr的累加和很大,並且m也很大,構造二維dp表顯然不達要求
* 但是arr的長度不大,意味著暴力解法有希望 (2^n) ,如果 30 < n < 35,
* 那麼整體暴力顯然不行,那麼可以拆成左右兩部分,分別去做,然後合併即可。
*/int
solution4
(int
* arr,
int n,
int m)
tmp--;}
ans = std::
max(ans, num + tmp);}
return ans;
}
四種方法,一起比較測試,如果有一點錯誤,屎都給你測出來了。
具體code:
// for test
void
test()
int m =
rand()
%100+1
;// [1, 100]if(
solution2
(arr, arrlen, m)
!=solution3
(arr, arrlen, m)
|| \
solution1
(arr, arrlen, m)
!=solution2
(arr, arrlen, m)
|| \
solution3
(arr, arrlen, m)
!=solution4
(arr, arrlen, m)
)delete
arr;
} std::cout <<
"test finish. \n\n"
;}
結果:具體問題,具體分析。
紙上得來終覺淺,絕知此事要躬行。
求陣列子串行和最大值
from 輸入一組整數,求出這組數字子串行和中的最大值,只要求出最大子串行的和,不必求出最大值對應的那個序列。序列 2 11 4 13 5 2 5 3 12 9 最大子串行和為21 序列 0 3 6 8 20 21 8 9 10 1 3 6 5 最大子串行和為43 如下 1 include2 usi...
上公升子串行 求和最大值
problem description 乙個只包含非負整數的序列bi,當b1 b2 bs的時候,我們稱這個序列是上公升的。對於給定的乙個序列,我們可以得到一些上公升的子串行,這裡1 i1 i2 ik n。例如 對於序列,有它的一些上公升子串行,如,等等。這些子串行中序列和最大的是子串行,它的所有元素...
求連續子串行的最大值
問題描述 有一串數字 可正可負的int,放在陣列num裡 要求找到起始位置start和終止位置end,使得從start位置到end位置的所有數字之和最大,返回這個最大值max。演算法思想 使用動態規劃。設 f x 為以 a x 終止且包含 a x 的最大序列的和,有 f 1 a 1 f x 1 f ...