POJ 1651 Multiplication Puzzle(区间DP)

题目:Multiplication Puzzle

    题意: 
    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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值