動態規劃 剪繩子 (JS 實現)
阿新 • • 發佈:2019-01-03
題目
現有一根長度為N的繩子,需要你剪成M段,使M段的乘積最大。(其中M、N都為整數,剪成的每段長度也為整數,N已知,M未知)。例如長度為8的繩子,當剪為3段乘積最大,即2*3*3=18.
思路
看到這種求最優解的題型,你就應該思考一下動態規劃是否適合。這個繩子我可以一次一次的剪,第一次剪成兩段,這就變成兩根新繩子,只要我分別知道這兩根新繩子最大的乘積,那麼我就知道了整條繩子的最大乘積了,這就將一個問題,劃分為兩個子問題了,且各子問題之間相互獨立,滿足最優子結構,因此可以使用動態規劃
首先確定邊界條件和狀態轉移方程:
- 當繩子長度為1時,最大乘積為0
- 當繩子長度為2時,可以剪成1*1,最大乘積為1
- 當繩子長度為3時,可以剪成(1*2,1*1*1),最大乘積為2
- 當繩子長度為4時,可以剪成(1*1*1*1, 1*2*1, 2*2, 1*3),最大乘積為4
- 當繩子長度為5時,可以剪成(1*1*1*1*1, 1*2*2, 3*2, 1*2*1*1, 1*3*1,1*4),最大乘積為6
我們可以看到,當繩子長度n大於等於4時,f(n) = max( f(i) * f(n-i) )
,其中1 < i <= [n/2]
,因此我們可以用遍歷來實現狀態轉移方程
程式碼
function LineMax(n){
if (n<=1) return 0;
if (n==2 ) return 1;
if (n==3) return 2;
const a =[0,1,2,3]; //排出前面的邊界條件,第i項表示長度為i的繩子的最大乘積
const b =[[0],[1],[2],[3]]; //第i項表示,長度為i繩子的最大乘積組合
for (var i=4;i<=n;i++){
a[i] = 0; //初始化
for (var j=1;j<= n/2;j++){ //迴圈找出最大乘積及組合並分別記錄在a,b陣列中
if (a[j]*a[i-j] >a[i]){
a[i] = a[j]*a[i-j];
b[i] = [...b[j], ...b[i-j]];
}
}
}
console.log(a[n]); //輸出長度為n的繩子最大乘積
console.log(b[n]); //輸出長度為n的繩子最大乘積時的劃分組合
}