经典问题二. (区间dp)石子归并 51nod 1021

来源:互联网 发布:java 数组去重的方法 编辑:程序博客网 时间:2024/06/10 05:20

51nod 1021 石子归并(区间dp)
问题描述:
N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。

思路:
区间dp通过区间的关系操作,从小区间到大区间。区间dp感觉有点像分治一样的,我们知道如果有两个数的话,那么其值就为两数相加,如果有大于两个的数,那么通过区间的合并的最优解能得到答案。
dp表示含义,与递推式,已代码注释。
AC代码
版本一:

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int INF = 0x3f3f3f3f;int dp[210][210]; //代表 区间i到j合并成一堆最小代价。int p[210][210]; //代表 区间i到j的和int a[210];int n;void init(){    for(int i = 1; i <= n; i++)    {        int sum = 0;        for(int j = i; j <= n; j++)        {            sum += a[j];            p[i][j] = sum;        }    }}int main(){    while(~scanf("%d",&n))    {        for(int i = 1; i <= n; i++)            scanf("%d",&a[i]);        init();        // 小区间 到 大区间        // dp[i][j] = dp[i][k]+dp[k+1][j]+a[k]+a[k+1];        memset(dp,0,sizeof(dp));        for(int len = 1; len < n; len++)        {            for(int i = 1; i+len <= n; i++)            {                int r = i, l = i+len;                dp[r][l] = INF;                for(int k = r; k < l; k++)                    dp[r][l] = min(dp[r][l],dp[r][k]+dp[k+1][l]+p[r][k]+p[k+1][l]);            }        }        printf("%d\n",dp[1][n]);    }    return 0;}

版本二:

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define INF 0x3f3f3f3f#define N 110int a[N];int dp[N][N];int sum[N];int main(){    int n;    scanf("%d",&n);    memset(dp,0,sizeof(dp));    memset(sum,0,sizeof(sum));    for(int i = 0; i < n; i++)    {        scanf("%d",&a[i]);        sum[i] = i==0?a[i]:a[i]+sum[i-1];    }    for(int i = n-1; i >= 0; i--)    {        for(int j = i; j < n; j++)        {            if(i == j) dp[i][j] = 0;            else            {                dp[i][j] = INF;                int x = sum[j] - (i==0?0:sum[i-1]);                for(int k = i; k <= j; k++)                    dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]+x);            }            //printf("%d ",dp[i][j]);        }        //puts("");    }    printf("%d\n",dp[0][n-1]);    return 0;}
0 0