石子合并(一)(区间dp)

传送门

题意:有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。

题解:使用区间dp,用dp[i][j]来表示合并第i堆到第j堆石子的最小代价,状态转移方程为dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]),其中w[i][j]表示把两部分合并起来的代价,即从第i堆到第j堆石子个数的和,为了方便查询,可以用sum[i]表示从第1堆到第i堆的石子个数和,那么w[i][j]=sum[j]-sum[i-1].


#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int maxn=205;

int n,x;
int sum[maxn];
int dp[maxn][maxn];

int main()
{
    while(~scanf("%d",&n)){
        sum[0]=0;
        memset(dp,0x3f,sizeof(dp));
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            sum[i]=sum[i-1]+x;
            dp[i][i]=0;
        }
        for(int len=2;len<=n;len++){
            for(int i=1;i<=n;i++){
                int j=i+len-1;
                if(j>n){
                    continue;
                }
                for(int k=i;k<j;k++){
                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
                }
            }
        }
        printf("%d\n",dp[1][n]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/81781486