ZOJ_Multiplication Puzzle DP

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1602 

题意:给定n个整数,除了两个边界(一头一尾)之外,将其他的n-2个数删除,每次删除一个数之后,将该数与其左边的、右边的数相乘的积作为其得分,求一个最小的得分和。

分析:在n个数中删除n-2个数,得到一个最小的得分,本题的DP产生思路是递归。用dp[i][j] 表示将a[i] 到a[j] 之间的数删除之后的最小得分,考虑最后一个删除的是a[k] ,则i+1 <= k <= j-1 , 则状态转移方程为:dp[i] [j] = min{ dp[i][k] + dp[k][j] + a[i]*a[k]*a[j] } ;


代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define min(a,b) (a>b?b:a) 
using namespace std;

int a[101],n;
int dp[101][101] ;

int DP()
{
	for(int i=1;i<n;i++)
	{
		dp[i][i+1] = 0 ;	
	}
	for(int len=3;len<=n;len++)
	{
		for(int i=1;i+len-1<=n;i++)
		{
			int j=i+len-1 ;
			if(len == 3)
			{
				dp[i][j] = a[i]*a[i+1]*a[i+2] ;	
				continue ;
			}
			dp[i][j] = 0x7fffffff ;
			
			for(int k=i+1;k<=j-1;k++)
			{
				dp[i][j] = min(dp[i][j],dp[i][k] + dp[k][j] + a[k]*a[i]*a[j]) ;
			}
		}	
	}
	
	return dp[1][n] ;		
}

int main()
{
    //freopen("1in.txt","r",stdin);
    //freopen("1out.txt","w",stdout);
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);	
		}	
		int ans = DP() ;
		printf("%d\n",ans );
	}

    return 0;
}


反思:这题一开始居然没有想到状态的表示,原因就是一直在纠结要怎么来表示每一个阶段。。 囧。。。

但是没有想到其实DP还有另外一种产生方法,那就是递归思想,由递归产生子问题。  还是没有真正理解DP啊,还得继续加油。。。。

你可能感兴趣的:(ZOJ_Multiplication Puzzle DP)