石子合并3

源代码:

#include<cstdio>
#include<algorithm>
using namespace std;
int n,Sum[401],f1[401][401],f2[401][401];
int main() //注意在本题中,f1[][]与f2[][]的作用进行了调换。
{
    scanf("%d",&n);
    for (int a=1;a<=n;a++)
      for (int b=1;b<=n;b++)
        f1[a][b]=f2[a][b]=1000000000; //奇怪的范围错误,看来以后遇到DP尽量手动赋值。
    for (int a=1;a<=n;a++)
    {
        int t;
        f2[a][a]=0;
        scanf("%d",&t);
        Sum[a]=Sum[a-1]+t; //前缀和。
    }
    for (int a=1;a<n;a++)
      f1[a][a+1]=Sum[a+1]-Sum[a-1]; //预处理只有两堆。
    for (int k=3;k<=n;k++)
      for (int a=1;a<=n-k+1;a++)
      {
        int t=a+k-1;
        for (int b=a;b<t;b++)
          f2[a][t]=min(f2[a][t],f1[a][b]+f2[b+1][t]+Sum[t]-Sum[b]);
        for (int b=a;b<t;b++)
          f1[a][t]=min(f1[a][t],f2[a][b]+f2[b+1][t]+Sum[t]-Sum[a-1]);
      }
    printf("%d",f2[1][n]);
    return 0;
}

/*
    做题还是要灵活转化。
    60分做法:
        在石子归并2的基础上改一改,断点变为两个,则有状态转移方程:
            f[i][j]=min{f[i][k1]+f[k1+1][k2]+f[k2+1][j]+S[j]-S[i-1]}
        时间复杂度为O(n^4);
    100分做法:
        在60分做法上优化就可以了,设辅助数组f2[i][j]=min{f1[i][k]+f1[k][j]},则有:
            f1[i][j]=min{f2[i][k]+f1[k+1][j]+S[j]-S[i-1]}
        并列的O(n^3)时间复杂度。
    做DP时应考虑转化以前做过的DP,并在此基础上进行修改和优化。
*/
原文地址:https://www.cnblogs.com/Ackermann/p/6037355.html