题意:
n个正整数a1~an,将除a1和an的数依次取出
假设取出的是a[i],则score += a[i-1]*a[i]*a[i+1]
按不同顺序取出各数会得到不同的score,
求最小的score
分析:
状态 :
dp[i][j]表示将区间[i,j]内(不含a[i]、a[j])拿走的最小score
边界 :
if (i+1 >= j) return 0;//区间长度不足3
if (i+1==j-1) return a[i]*a[i+1]*a[j];//区间刚好3个数
状态转移:
考虑在区间[i,j]中最后拿走的数 (3种情况)
首先明确的是,要拿走的数是a[i+1]~a[j-1]
1.最后拿走a[i+1] :dp[i][j] = a[i]*a[i+1]*a[j] + dp[i+1][j];
2.最后拿走a[j-1] :dp[i][j] = a[i]*a[j-1]*a[j] + dp[i][j-1];
3.最后拿走a[k](i+1<k<j-1):dp[i][j] = a[i]*a[k]*a[j] + dp[i][k] + dp[k][j]
【将区间[i,k]和区间[k,j]全部拿完留下a[k]最后拿(因为在分成的两个区间中都是边界故没有被拿走)】
#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Sint(n) scanf("%d",&n)
#define Sll(n) scanf("%I64d",&n)
#define Schar(n) scanf("%c",&n)
#define Sint2(x,y) scanf("%d %d",&x,&y)
#define Sll2(x,y) scanf("%I64d %I64d",&x,&y)
#define Pint(x) printf("%d",x)
#define Pllc(x,c) printf("%I64d%c",x,c)
#define Pintc(x,c) printf("%d%c",x,c)
using namespace std;
typedef long long ll;
/*
题意:
n个正整数a1~an,将除a1和an的数依次取出
假设取出的是a[i],则score += a[i-1]*a[i]*a[i+1]
按不同顺序取出各数会得到不同的score,
求最小的score
分析:
状态 :
dp[i][j]表示将区间[i,j]内(不含a[i]、a[j])拿走的最小score
边界 :
if (i+1 >= j) return 0;//区间长度不足3
if (i+1==j-1) return a[i]*a[i+1]*a[j];//区间刚好3个数
状态转移:
考虑在区间[i,j]中最后拿走的数 (3种情况)
首先明确的是,要拿走的数是a[i+1]~a[j-1]
1.最后拿走a[i+1] :dp[i][j] = a[i]*a[i+1]*a[j] + dp[i+1][j];
2.最后拿走a[j-1] :dp[i][j] = a[i]*a[j-1]*a[j] + dp[i][j-1];
3.最后拿走a[k](i+1<k<j-1):dp[i][j] = a[i]*a[k]*a[j] + dp[i][k] + dp[k][j]
【将区间[i,k]和区间[k,j]全部拿完留下a[k]最后拿(因为在分成的两个区间中都是边界故没有被拿走)】
*/
const int N = 111;
int dp[N][N];
int a[N];
int DP(int i,int j)
{
if (i+1>=j) return 0;
if (~dp[i][j]) return dp[i][j];
if (i+1==j-1) return dp[i][j] = a[i]*a[i+1]*a[j];
// 第一种情况
dp[i][j] = a[i]*a[i+1]*a[j] + DP(i+1,j);
//第二种情况
dp[i][j] = min(dp[i][j],a[i]*a[j-1]*a[j]+DP(i,j-1));
//第三种情况
for (int k = i+2;k < j-1;++k)
{
dp[i][j] = min(dp[i][j],a[i]*a[k]*a[j]+DP(i,k)+DP(k,j));
}
return dp[i][j];
}
int main()
{
mem(dp,-1);
int n;
while (Sint(n)==1)
{
for (int i = 1;i <= n;++i) Sint(a[i]);
Pintc(DP(1,n),'\n');
}
return 0;
}