CSP 2016-12-4 压缩编码

转载https://blog.csdn.net/tigerisland45/article/details/61622152

这是一个编码问题,似乎可以用哈夫曼编码来解决,但是略有不同的地方在于“每个字符的编码按照字典序排列后的顺序与原先顺序一样”。

所以无法每次取出权值最小的两个节点,而只能选择相邻的节点,到底选择哪两个相邻节点,这便是石子问题

设dp[i][j]表示第i到第j堆石子合并的最优值,sum[i][j]表示第i到第j堆石子的总数量。那么就有状态转移公式:

1、dp[i][j]=0 (i==j)

2、dp[i][j]=min(dp[i][k]+dp[k][j])+sum[i][j] (i!=j)

此时算法复杂为O(n^3)。

这里可以利用平行四边形优化降为O(n^2):

由上面的方程式可知我们每次求dp[i][j]的关键是找到合适的k值,设p[i][j]为dp[i][j]的这个合适的k值,根据平行四边形规则有以下不等式:p[i][j-1]<=p[i][j]<=p[i+1][j]。

那么求解dp[i][i+L](L为长度)的复杂度就为:

(p[2,L+1]-p[1,L])+(p[3,L+2]-p[2,L+1])…+(p[n-L+1,n]-p[n-L,n-1])=p[n-L+1,n]-p[1,L]≤n。

复杂度为O(n)。然后L从1循环至n,总复杂度就为O(n^2)。

程序说明。:程序中,INT_MAX2值是个将就的做法,并不是整数最大值。
这里给出了两个代码程序,后一种做了优化,速度快了非常多。前一个程序运行时间是秒级的,后一个程序运行时间是毫秒级的。

/* CCF201612-4 压缩编码 */
 
#include <iostream>
#include <cstring>
 
using namespace std;
 
const int INT_MAX2 = 0x7F7F7F7F;
const int N = 1000;
 
int v[N+1];
int sum[N+1];
int dp[N+1][N+1];
 
int solve(int l, int r)
{
    if(dp[l][r] == INT_MAX2)
        for(int i = l; i < r; i++)
            dp[l][r] = min(dp[l][r], solve(l, i) + solve(i+1, r) + sum[r] - sum[l-1]);
 
    return dp[l][r];
}
 
int main()
{
    int n;
 
    // 变量初始化:置为最大值
    memset(dp, INT_MAX2, sizeof(dp));
 
    // 输入数据
    cin >> n;
    sum[0] = 0;
    for(int i=1; i<=n; i++) {
        cin >> v[i];
 
        sum[i] = sum[i-1] + v[i];
        dp[i][i] = 0;
    }
 
    // DP计算
    solve(1, n);
 
    // 输出结果
    cout << dp[1][n] << endl;
 
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值