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啊,还得继续加油。。。。