POJ 1651 Multiplication Puzzle(区间DP)

一道比较经典的区间DP,和这题一样:点击打开链接

用dp[i][j] 表示消掉区间[i,j]内所有数字后的最优解。   那么状态转移为ans = min(ans,dp(i,k-1)+a[k]*a[i-1]*a[j+1]+dp(k+1,j)); 这个状态转移表示的是对于区间[i,j]最后杀k。  为什么要这么转移呢?  因为你选择的这个数字,其左右的数字会对其产生影响,而这样表示就可以巧妙的消除这个影响,而把问题转移给其子问题。既然最后选择k那么获得的分数自然就是a[k]*a[i-1]*a[j+1] 了。

细节参见代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<numeric>
#include<functional>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<cassert>
#include<complex>
#include<iomanip>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 205;
const int INF = 1000000000;
int T,n,kase=0,a[maxn],b[maxn],d[maxn][maxn];
int dp(int i, int j) {
    if(i > j) return 0;
    int& ans = d[i][j];
    if(ans != -1) return ans;
    ans = INF;
    for(int k=i;k<=j;k++) ans = min(ans,dp(i,k-1)+a[k]*a[i-1]*a[j+1]+dp(k+1,j));
    return ans;
}
int main() {
    while(~scanf("%d",&n)) {
        memset(d,-1,sizeof(d));
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        a[n+1] = b[n+1] = 1;
        int ans = dp(2,n-1);
        printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(dp,poj,ACM-ICPC)