洛谷Oj-石子合并-区间动态规划

来源:互联网 发布:内卷化 知乎 编辑:程序博客网 时间:2024/05/21 09:36

问题描述
在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.
AC代码

int a[205],sum[205],dpmax[205][205],dpmin[205][205];//数组a记录石子堆的大小(注意数组要开两倍大),sum[i]记录第1到第i堆石子的总大小,数组dpmax用来求最大得分,数组dpmin用来求最小得分int max1(int a,int b)//取较大比较函数{    return a>b?a:b;}int min1(int a,int b)//取较小比较函数{    return a<b?a:b;}int main(){    int n,i,j,k,max=-inf,min=inf,len;//初始化变量max、min,len代表区间的长度    scanf("%d",&n);//输入    for(i=1;i<=n;i++)    {        scanf("%d",&a[i]);        a[n+i]=a[i];//倍增(详见②)    }    for(i=1;i<=2*n;i++)//前缀和(部分和)        sum[i]=sum[i-1]+a[i];    for(len=2;len<=n;len++)//区间动态规划关键代码,len代表区间的长度,注意是从2到n        for(i=1;i+len-1<=2*n-1;i++)//枚举区间起点(i),注意不能越界(即区间终点不能超过2*n-1)        {            j=i+len-1;//通过i与len计算出区间终点j            dpmax[i][j]=-inf;//为接下来的比较做准备            dpmin[i][j]=inf;            for(k=i;k<=j-1;k++)//k为区间中的一点,将区间[i,j]分成[i,k]和[k+1,j],注意k的取值是从i到j-1(保证k+1不越界)            {                dpmax[i][j]=max1(dpmax[i][j],dpmax[i][k]+dpmax[k+1][j]+sum[j]-sum[i-1]);                dpmin[i][j]=min1(dpmin[i][j],dpmin[i][k]+dpmin[k+1][j]+sum[j]-sum[i-1]);            }        }    for(i=1;i<=n;i++)//比较各个区间(长度为n)的最值    {        max=max1(max,dpmax[i][i+n-1]);        min=min1(min,dpmin[i][i+n-1]);    }    printf("%d\n%d\n",min,max);//打印    return 0;}

解决方法
①涉及到了前缀和(部分和)这个知识点
②一种破环成链的方法:倍增。注意相关数组开两倍大,实际上用到的只是1到2*n-1
样例
③并不需要将dp[i][i]赋值为0,因为如果i==j,即i==i+len-1,得出len==1,这是不存在的
④区间dp模板
⑤此题可以应用四边形不等式来优化,将O(n^3)降为O(n^2)

原创粉丝点击