分段动态规划(SOJ 1162)

SOJ 1162: I-Keyboard http://acm.scu.edu.cn/soj/problem.action?id=1162

Given a string $S$ with length $L$ in which each character has a frequency $F[i], 0\le i<L$, the target is to partition $S$ into $K$ segments satisfying that the sum of products is minimized. For each segment, each character has a position $P[i]$ from $1$ to its length.

String:         $S[0], \dots, S[i_{1}]$ | $S[i_{1}+1], \dots, S[i_{2}]$ | $\dots$ | $S[i_{K-1}+1], \dots, S[i_{K}]$ $(S[L-1])$

Segment:             $1$             |                   $2$           | $\dots$ |                      $K$

Position:      $1, \dots, i_{1}+1$   |     $1, \dots, i_{2}-i_{1}$       | $\dots$ |     $1, \dots, i_{K}-i_{K-1}$

Frequency: $F[0], \dots, F[i_{1}]$ | $F[i_{1}+1], \dots, F[i_{2}]$ | $\dots$ | $F[i_{K-1}+1], \dots, F[i_{K}]$ $(F[L-1])$

The definition of sum of products cost is as follows:

$cost=\Sigma P[i]*F[i].$

This problem is one dynamic programming problem. The optimal substructure is that: if $cost(K, i_{K})$ is the optimal solution of string $S[0, \dots, i_{K}]$ with $K$ segments, then $cost(K-1, i_{K-1})$ is the optimal solution of string $S[0, \dots, i_{K-1}]$ with $K-1$ segments. Define $cost[i][j]$ as the optimal solution for string $S[0, \dots, j]$ with $i$ segments, then we have the state transition equation:

$cost[i][j]=\min\{cost[i-1][k]+\sum_{t=k+1}^{j}(t-k)*F[t], k=i-1, \dots, j-1\}.$

That is, serve each $S[k+1, \dots, j], k=i-1, \dots, j-1$ as the $i$-th segment. Here there is one point we need to pay attention to, the calculation of $\sum_{t=k+1}^{j}(t-k)*F[t]$. Notice that

$\sum_{t=k+1}^{j}(t-k)*F[t]=\sum_{t=k+1}^{j}t*F[t]-k\sum_{t=k+1}^{j}F[t]$,

thus we can use the cumulative sum technique to deal with it.

The whole code is as follows:

#include<iostream>
using namespace std;
char key[95];
char letter[95];
int weight[95];
int cost[95][95];
int flag[95][95];
int position[95];
int sum1[95];
int sum2[95];
int main()
{
    int T;
    scanf("%d",&T);
    int K,L;
    int i,j,k,t;
    int tarVal;
    int temp;
    for(t=1;t<=T;t++)
    {
        scanf("%d%d",&K,&L);
        scanf("%s",key);
        scanf("%s",letter);
        scanf("%d",&weight[0]);
        sum1[0]=weight[0];
        sum2[0]=weight[0];
        for(j=1;j<L;j++)
        {
            scanf("%d",&weight[j]);
            sum1[j]=sum1[j-1]+weight[j]*(j+1);
            sum2[j]=sum2[j-1]+weight[j];
        }
        cost[0][0]=weight[0];
        for(j=1;j<L;j++)
            cost[0][j]=sum1[j];
        for(i=1;i<K;i++)
            for(j=i;j<L;j++)
            {
                tarVal=0x3f3f3f3f;
                for(k=i-1;k<=j-1;k++)
                {
                    temp=cost[i-1][k]+sum1[j]-sum1[k]-(k+1)*(sum2[j]-sum2[k]);
                    if(temp<tarVal)
                    {
                        tarVal=temp;
                        flag[i][j]=k+1;
                    }
                }
                cost[i][j]=tarVal;
            }
        temp=L-1;
        for(i=K-1;i>0;i--)
        {
            position[i]=flag[i][temp];
            temp=position[i]-1;
        }
        position[0]=0;
        position[K]=L;
        printf("Keypad #%d:\n",t);
        for(i=0;i<K;i++)
        {
            printf("%c: ",key[i]);
            for(j=position[i];j<position[i+1];j++)
                printf("%c",letter[j]);
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ClearMoonlight/p/10508344.html

时间: 2024-10-10 13:01:49

分段动态规划(SOJ 1162)的相关文章

总结-数学

数学 比较害怕数学题, 因为数学题一般代码比较短, 一旦想到正解往往就能AC, 但是我数学水平很洼, 知道的东西也比较少. 感觉写写暴力拿部分分比较现实. 毕竟不是每个人都能找到正解. 1. 组合数 一般用阶乘计算, 需要求逆元. 可以用lucas定理优化时间复杂度. 组合类的问题就要考虑组合数 1. BestCoder-Round#33 第二题是组合数的题目 2. BZOJ-1005-明明的烦恼 用组合数阶乘公式推导出最后的式子 3. BZOJ-1951-古代猪文-SDOI2010-费马小定理

区间动态规划-DFS种类数(SOJ 2469)

2469: Exploring Pyramids 问题:给出一棵树我们可以写出它的深搜结果,现在给出深搜结果字符串$S$求解对应树的种类数. 例子:深搜结果:$ABABABA$,对应的树(根结点在底层)有$5$个. 分析:应用区间动态规划,定义$dp[i][j]$为$S[i..j]$对应的树的个数,则分两类: (1)$S[i]$有一个子结点(上例中前两种情况),$S[i..j]$对应的树的个数就等于$S[i+1..j-1]$对应的树的个数,前提是$S[i]=S[j]$.即,若$S[i]=S[j]

【算法导论】用动态规划解活动选择问题

上一篇讲了贪心算法来解活动选择问题([算法导论]贪心算法之活动选择问题),发现后面有一道练习16.1-1是要用动态规划来解活动选择问题.其实跟之前的矩阵链乘法有些相似,也是考虑分割的活动是哪一个,并用二维数据来记录Sij---最大兼容集合个数,和用另一个二维数据来记录Sij取得最大时的活动分割点k.然后就是考虑边界问题,和使用递归来求动态规划的最优解. 代码注解比较详尽: #include <iostream> #include <algorithm> using namespac

转载:动态规划

来源:http://blog.sina.com.cn/s/blog_7727572f01011461.html 动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法.20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问

POJ1141 Brackets Sequence (dp动态规划,递归)

本文出自:http://blog.csdn.net/svitter 原题:http://poj.org/problem?id=1141 题意:输出添加括号最少,并且使其匹配的串. 题解: dp [ i ] [ j ] 表示添加括号的个数, pos[ i][ j ] 表示 i , j 中哪个位置分开,使得两部分分别匹配. pos [ i ][ j ] 为-1的时候,说明i, j 括号匹配. 初始值置dp [ i ] [ i ]  = 1; 如果只有一个括号,那么匹配结果必然是差1. 首先判断括号是

Soj题目分类

-----------------------------最优化问题------------------------------------- ----------------------常规动态规划  SOJ1162 I-Keyboard  SOJ1685 Chopsticks SOJ1679 Gangsters SOJ2096 Maximum Submatrix  SOJ2111 littleken bg SOJ2142 Cow Exhibition  SOJ2505 The County

java——递归(动态规划,回溯)

最近刷面试题经常刷到递归方面的算法,一直以为都是递归,后来发现竟然都有具体的叫法,所以写了这篇博客来牢记以下 1. 五大常用算法 (1) 分治算法 把一个复杂的问题分成两个或多个相同或者相似的子问题,然后不断地细分,直到最后的子问题可以很简单地求解出来,原问题的解就是自问题的合并.比如常见的快速排序算法和归并算法 分治法的核心思想就是把大的难解的问题不断分割,分而治之. (2) 动态规划 类似于分治法,将带求解的问题分化成几个小问题,每个小问题的解会影响原问题的解. 先求每个子问题的局部解,然后

【算法导论】动态规划之“钢管切割”问题

动态规划,其实跟分治法有些相似,基本思想都是将复杂的问题分成数个简单的子问题,然后再去解决.它们的区别在于,分治法关注的子问题不相互"重叠",而动态规划关注的子问题,多是相互"重叠"的.比如在快速排序中,我们将数据分成两部分,这两部分再分别快速排序的递归思想,也就是将整个问题的排序划分为子问题子数组的排序,但是这两个子数组的排序之间并没有相互联系,a子数组的排序不会因为b子数组的排序而得到任何"好处"或者"坏处".但是有些时候

poj 3744 Scout (Another) YYF I - 概率与期望 - 动态规划 - 矩阵快速幂

(Another) YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate into the enemy's base. After overcoming a series difficulties, (Another) YYF is now at the start of enemy's famous "mine road". This is a very long road,