洛谷P1880 四边形不等式优化石子合并

题意:

给定圆周上的nnn堆石子,每一堆有wiw_{i}wi个石头,合并两堆的代价为两堆的石头总数之和,问合并所有堆为一堆的最小代价。

O(n2)O(n^2)O(n2)做法:

转移方程形如dp[i][j]=min(dp[i][k],dp[k+1][j])+w[i][j]dp[i][j]=min(dp[i][k],dp[k+1][j])+w[i][j]dp[i][j]=min(dp[i][k],dp[k+1][j])+w[i][j]的转移方程,可以用四边形不等式优化,将O(n3)O(n^3)O(n3)的复杂度降为O(n2)O(n^2)O(n2)其中必须是minminminw[i][j]w[i][j]w[i][j]表示处理区间为[i,j][i,j][i,j]的贡献。

四边形不等式:

l≤l′≤r′≤rl \leq l' \leq r' \leq rllrr,有w[l′][r′]≤w[l][r]w[l'][r'] \leq w[l][r]w[l][r]w[l][r]w[l][r′]+w[l′][r]≤w[l][r]+w[l′][r′]w[l][r']+w[l'][r]\leq w[l][r]+w[l'][r']w[l][r]+w[l][r]w[l][r]+w[l][r]成立,就有如下的不等式成立:

s[l][r−1]<=s[l][r]<=s[l][r+1]s[l][r-1]<=s[l][r]<=s[l][r+1]s[l][r1]<=s[l][r]<=s[l][r+1],其中s[l][r]s[l][r]s[l][r]表示为[l,r][l,r][l,r]的最佳决策点,即使dp[l][k]+dp[k+1][j]dp[l][k]+dp[k+1][j]dp[l][k]+dp[k+1][j]最小的kkk

那么,我们计算dp[i][j]dp[i][j]dp[i][j]时,我们只需要在[s[i][j−1],s[i+1][j]][s[i][j-1],s[i+1][j]][s[i][j1],s[i+1][j]]中枚举kkk即可,假设我们在j−ij-iji恒定的情况下枚举,也就是按顺序枚举dp[i][j],dp[i+1][j+1],dp[i+2][j+2],...,dp[n−(j−i+1)+1][n]dp[i][j],dp[i+1][j+1],dp[i+2][j+2],...,dp[n-(j-i+1)+1][n]dp[i][j],dp[i+1][j+1],dp[i+2][j+2],...,dp[n(ji+1)+1][n]

我们分别需要在

[s[i][j−1],s[i+1][j]][s[i][j-1],s[i+1][j]][s[i][j1],s[i+1][j]]

[s[i+1][j],s[i+2][j+1]][s[i+1][j],s[i+2][j+1]][s[i+1][j],s[i+2][j+1]]

...............

[s[n−(j−i+1)+1][n−1],s[n−(j−i+1)+1−1][n]][s[n-(j-i+1)+1][n-1],s[n-(j-i+1)+1-1][n]][s[n(ji+1)+1][n1],s[n(ji+1)+11][n]]

中枚举kkk,发现这些区间首尾相连,总长度为s[n−l+2][n]−s[1][l−1]+n−l+1≤n+n=2ns[n-l+2][n]-s[1][l-1]+n-l+1\leq n+n=2ns[nl+2][n]s[1][l1]+nl+1n+n=2n

所以我们给定计算区间的长度,可以在O(n)O(n)O(n)时间内计算完所有的这个长度的dpdpdp值,枚举长度也是O(n)O(n)O(n),总复杂度是O(n2)O(n^2)O(n2)

最大值:

性质:dp[i][j]dp[i][j]dp[i][j]的最大值总是在合并端点处取得,也就是max(dp[i+1][j],dp[i][j−1])max(dp[i+1][j],dp[i][j-1])max(dp[i+1][j],dp[i][j1])

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int n,w[205],sum[205],dp[205][205],s[205][205];
int inf=0x3fffffff,ans=inf;

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>w[i];
        sum[i]=sum[i-1]+w[i];
        s[i][i]=i;
    }
    for(int i=n+1;i<=2*n;i++)
    {
        w[i]=w[i-n];
        s[i][i]=i;
        sum[i]=sum[i-1]+w[i];
    }
    auto getvalue=[&](int l,int r)
    {
        return sum[r]-sum[l-1];
    };    
    for(int i=1;i<=2*n;i++)
    {
        // for(int j=1;j<=2*n;j++) dp[i][j]=inf;
        dp[i][i]=0;
    }
    for(int i=2*n-1;i>=1;i--)
        for(int j=i+1;j<=2*n;j++) dp[i][j]=min(dp[i+1][j],dp[i][j-1])+getvalue(i,j);
    for(int i=1;i<=n;i++) ans=min(ans,dp[i][i+n-1]);
    cout<<ans<<endl;
    for(int i=2*n-1;i>=1;i--)
        for(int j=i+1;j<=2*n;j++) dp[i][j]=max(dp[i+1][j],dp[i][j-1])+getvalue(i,j);
    ans=-1;
    for(int i=1;i<=n;i++) ans=max(ans,dp[i][i+n-1]);
    cout<<ans;
    return 0;    
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值