動規之刪數問題
阿新 • • 發佈:2018-12-09
刪數問題
問題描述
現有n個正整陣列成的序列a,從中刪除一個數,得分是其本身同左、右相鄰的數的乘積,
然後再在剩餘的整數中繼續刪除,注意序列兩端的數字a1和an是不能刪除的,求這樣刪除n-2個整數後的最大得分。
例如有四個數3 、4、5、6,按照先4後5的刪除順序,其得分為345+356=150,
按照先5後4的刪除順序,其得分為456+346=192,因此最大得分為192。
測試樣例:
-
第一組
4
3 4 5 6 -
第二組
5
3 6 7 8 2
問題分析
----又是一個典型的區間動規。
最優子結構:
dp[i][j] = dp[i][k] + dp[k][j] + a[i] * a[k] * a[j];
對於第i個物品到第j個物品,假設最後刪掉k得到的結果最大,那麼最後一次刪除時,得到的分數就是 a[i] * a[k] * a[j]。那麼總的得分就是需要加上之前刪掉k的左右兩邊除了i,j之外所有數的和,即dp[i][j] 的兩個子問題,分別是dp[i][k] 和dp[k][j]。由此便可得出上面所寫的最優子結構
程式碼
/*
刪數問題:
現有n個正整陣列成的序列a,從中刪除一個數,得分是其本身同左、右相鄰的數的乘積,
然後再在剩餘的整數中繼續刪除,注意序列兩端的數字a1和an是不能刪除的,求這樣刪除n-2個整數後的最大得分。
例如有四個數3 、4、5、6,按照先4後5的刪除順序,其得分為3*4*5+3*5*6=150,
按照先5後4的刪除順序,其得分為4*5*6+3*4*6=192,因此最大得分為192。
測試樣例:
4
3 4 5 6
5
3 6 7 8 2
*/
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX_N 1010
static int a[MAX_N];//用來儲存序列
static int dp[MAX_N][MAX_N];//i j 用來儲存刪除第i個數到第j個數所得到的最優值
void dp1(int n)
{
int j = 0;
for(int r = 3;r <= n;r ++ ){
for(int i = 1;;i ++ ){
int j = i + r -1;
for(int k = i + 1;k <= j - 1;k ++ ){
dp[i][j] = max(dp[i][j],dp[i][k]+dp[k][j]+a[i]*a[k]*a[j]);
}
if(j >= n) break;
}
}
cout << "刪除n-2個數之後,得到的最大值為:" << endl;
cout << dp[1][n] << endl;
}
int main()
{
int n;
cout << "請輸入序列的位數n" << endl;
while(cin >> n,n){
for(int i = 1;i <= n;i ++ ){
cin >> a[i];
}
memset(dp,0,MAX_N*MAX_N);
for(int i = 1;i <= n - 1;i ++ ){
dp[i][i + 1] = 0;
}
dp1(n);
cout << "請輸入序列的位數n" << endl;
}
return 0;
}