2889. 再探石子合并

题目链接

2889. 再探石子合并

设有 N 堆石子排成一排,其编号为 123N

每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。

每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。

例如有 4 堆石子分别为 1 3 5 2, 我们可以先合并 12 堆,代价为 4,得到 4 5 2, 又合并 12 堆,代价为 9,得到 9 2 ,再合并得到 11,总代价为 4+9+11=24

如果第二步是先合并 23 堆,则代价为 7,得到 4 7,最后一次合并代价为 11,总代价为 4+7+11=22

问题是:找出一种合理的方法,使总的代价最小,输出最小代价。

输入格式

第一行一个数 N 表示石子的堆数 N

第二行 N 个数,表示每堆石子的质量(均不超过 1000)。

输出格式

输出一个整数,表示最小代价。

数据范围

1N5000

输入样例:

4 1 3 5 2

输出样例:

22

解题思路

四边形不等式优化dp

本题是二维四边形不等式的优化dp模板题

f[i][j]=minik<j{f[i][k]+f[k+1][j]+w[i][j]},其中 f[i][i]=w[i][i]=0,如果 w 满足四边形不等式,且对于任意的 abcd,都有 w(a,d)w(b,c),则 f 也满足四边形不等式

证明:
这里应用数学归纳法证明:

  1. 首先先证明 ji=1 的情况,对于 i<i+1=j<j+1,即要证明 f[i][j+1]+f[i+1][j]f[i][j]+f[i+1][j+1],而 f[i][j+1]+f[i+1][j]=f[i][i+2]+f[i+1][i+1]=f[i][i+2],这时枚举 f[i][i+2] 的最优决策,假设其最优决策为 i,则有 f[i][i+2]=f[i][i]+f[i+1][i+2]+w(i,i+2)=w(i+1,i+2)+w(i,i+2)w(i+1,i+2)+w(i,i+1)=f[i+1][i+2]+f[i][i+1]=f[i+1][j+1]+f[i][j],满足要求;其最优决策为 i+1 时同理可得
  2. ji<k 时,f 满足四边形不等式,要证 ji=kf 也满足四边形不等式
    假设 x,y 分别为 f[i][j+1],f[i+1][j] 的最优决策,设 ixy,则有:
    对于 f[i][j+1]+f[i+1][j] 有:
    f[i][j+1]+f[i+1][j]=f[i][x]+f[x+1][j+1]+w(i,j+1)+f[i+1][y]+f[y+1][j]+w(i+1,j)
    对于 f[i][j]+f[i+1][j+1] 有:
    f[i][j]+f[i+1][j+1]f[i][x]+f[x][i]+w(i,j)+f[i+1][y]+f[y+1][j+1]+w(i+1,j+1)
    又因为 w 满足四边形不等式,即 w(i,j+1)+w(i+1,j)w(i,j)+w(i+1,j+1)
    又因为 x+1y+1j<j+1,这里面先验证是否有 j(x+1)<k,因为 ji=k,ix,即 jkx,即 j(x+1)<k,故这种状态满足四边形不等式,得:f[x+1][j+1]+f[y+1][j]f[x+1][j]+f[y+1][j+1],则比较 f[i][j+1]+f[i+1][j]f[i][j]+f[i+1][j+1] 转化后的式子,可得 f[i][j+1]+f[i+1][j]f[i][j]+f[i+1][j+1],其他情况同理

二维决策单调性:设 p[i][j]f[i][j] 的最优决策,如果 f 满足四边形不等式,则对于任意的 i<j,都有 p[i][j1]p[i][j]p[i+1][j]

证明:
p=p[i][j],对于任意的 i<i+1kp,由 f 的四边形不等式,得 f[i][p]+f[i+1][k]f[i][k]+f[i+1][p],即有 f[i+1][k]f[i+1][p]f[i][k]f[i][p],又因为 pf[i][j] 的最优决策,则有 f[i][k]+f[k+1][j]f[i][p]+f[p+1][j],则有 f[i+1][k]+f[k+1][j]+w(i+1,j)(f[i+1][p]+f[p+1][j]+w(i,j+1))=(f[i+1][k]f(f[i+1][p])+(f[k+1][j]f[p+1][j])(f[i][k]f[i][p])+(f[k+1][j]f[p+1][j])=(f[i][k]+f[k+1][j])(f[i][p]+f[p+1][j])0,即对于 f[i+1][j] 来说,pkp 更优,则有 p[i][j]p[i+1][j],同理可证 p[i][j1]p[i][j]

复杂度分析:复杂度为 O(l=1n1r=l+1n(p[l+1][r]p[l][r1]+1)),不难发现,除非 l=1r=n,其他都会消去,所以最后最多剩下 O(n),效果,且每一项都是 O(n) 规模,则:

  • 时间复杂度:O(n2)

代码

// Problem: 再探石子合并 // Contest: AcWing // URL: https://www.acwing.com/problem/content/2892/ // Memory Limit: 256 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=5005; int n,s[N],f[N][N],p[N][N]; int main() { scanf("%d",&n); memset(f,0x3f,sizeof f); for(int i=1;i<=n;i++)scanf("%d",&s[i]),s[i]+=s[i-1],p[i][i]=i,f[i][i]=0; // for(int len=2;len<=n;len++) // for(int l=1;l+len-1<=n;l++) for(int l=n;l>=1;l--) for(int r=l+1;r<=n;r++) { for(int k=p[l][r-1];k<=p[l+1][r];k++) if(f[l][r]>=f[l][k]+f[k+1][r]+s[r]-s[l-1]) { f[l][r]=f[l][k]+f[k+1][r]+s[r]-s[l-1]; p[l][r]=k; } } printf("%d",f[1][n]); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16972550.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
历史上的今天:
2021-12-10 2983. 玩具
点击右上角即可分享
微信分享提示