計蒜客 213 乘法遊戲
阿新 • • 發佈:2018-12-23
乘法遊戲
通過率: 8.33% 時間限制: 1000ms 記憶體限制: 65536K
關鍵詞: 區間DP
Description
乘法遊戲是在一行牌上進行的。每一張牌包括了一個正整數。在每一個移動中,玩家拿出一張牌,得分是用它的數字乘以它左邊和右邊的數,所以不允許拿第1張和最後1張牌。最後一次移動後,這裡只剩下兩張牌。你的目標是使得分的和最小。
例如,如果數是10 1 50 20 5,依次拿1、20、50
總分是 10150+50205+10505=8000
而拿50、20、1,總分是15020+1205+1015=1150。
Input
輸入檔案的第一行包括牌數(3< =n< =100),第二行包括N個1-100的整數,用空格分開。
Output
輸出檔案只有一個數字:最小得分
SampleInput
6
10 1 50 50 20 5
SampleOutput
3650
Analyze
區間DP:
dp[i][j]表示區間[i,j]的最小值.
在 [i, j] 區間中:
- dp[i][k] 算出 (i, k) 區間中的最小值,最後剩下 a[i], a[k]
- dp[k][j] 算出 (k, j) 區間中的最小值,最後剩下 a[k], a[j]
- 最後在 [i, j] 區間中就只剩下 dp[i][k], dp[k][j] 以及 a[i], a[k], a[j],
dp[i][j] = dp[i][k] + dp[k][j] + a[i]*a[k]*a[j] (i < k < j)
由於K是(i, j)內的任意值。所以:
dp[i][j] = min(dp[i][k]+dp[k][j]+a[i]*a[k]*a[j], dp[i][j]);
Code
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<algorithm>
#include <limits.h>
using namespace std;
int dp[110][110];
int arr[110];
const int INF=2147483647; //2147483647
int main()
{
int n;
// freopen("E:\\in.txt", "r", stdin);//輸入重定向,輸入資料將從in.txt檔案中讀取
// freopen("E:\\out2.txt", "w", stdout);//輸出重定向,輸出資料將儲存在out.txt檔案中
while(scanf("%d",&n)!=EOF)
{
for(int i=0; i<n; i++)
scanf("%d",&arr[i]);
for(int i=0; i<n-1; i++)//當[i,j]區間長度為3的時候我們需要相鄰的dp[i][j]==0(j-i==1)
dp[i][i+1] = 0;
for(int len=3; len<=n; len++) //區間長度(最小3,最大n)
{
for(int i=0; i<n-2; i++) //列舉區間起點
{
int j=i+len-1; //區間終點(3<=j<=n+n-1)
if(j >= n) break; //我們最多算dp[0, n-1]
dp[i][j] = INF;
for(int k=i+1; k<j; k++)
dp[i][j]=min(dp[i][k]+dp[k][j]+arr[i]*arr[k]*arr[j],dp[i][j]);
}
}
printf("%d\n",dp[0][n-1]);
}
return 0;
}