链接: https://nanti.jisuanke.com/t/213
乘法游戏
通过率: 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;
}
原文链接:http://blog.ttxxly.top/2017/05/24/jisuanke-213-乘法游戏/#more