• 8.17 动态规划——书的抄写


    求贤若渴,虚心前行。

    今天为大家整理一道动态规划的经典题目——书的抄写,是一道经典的二维线性dp问题,一起看一下吧。

    题目描述

    编辑部想要把 M 本书有顺序地分给 K 个人抄写,所有人的抄写速度相同,一本书不允许给两个(或以上)的人抄写,分给每一个人的书必须是连续的,比如不能把第一、第三、第四本数给同一个人抄写。现在请设计一种方案,使得抄写时间最短。抄写时间为抄写页数最多的人用去的时间。

     

    输入

    第 1 行 2 个整数 M 和 K,K≤M≤500,之间用一个空格隔开。
    第 2 行 M 个整数,第 i 个整数表示第 i 本书的页数,之间用一个空格隔开。
     


    输出

    共 K 行,每行 2 个正整数,第 i 行表示第 i 个人抄写的书的起始编号和终止编号,每两个数之间用一个空格隔开。K 行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。 


    样例说明: 
    三个人抄书的位置分别为: 
    1-5 (15页) 
    6-7 (13页) 
    8-9 (17页)  
     


    样例输入

    9 3
    1 2 3 4 5 6 7 8 9

     

    样例输出

    1 5
    6 7
    8 9

    题解代码:

    #include<iostream>
    #include<cstring>
    using namespace std;
    int m,k,a[505],dp[505][505],sum[505],path[505][505];
    void print(int i,int j){
        if(i==0) return ;
        print(i-1,path[i][j]);
        printf("%d %d ",path[i][j]+1,j);
    }
    int main(){
        scanf("%d%d",&m,&k);
        for(int i=1;i<=m;i++){
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        memset(dp,0x3f,sizeof(dp));
        for(int i=1;i<=m-k+1;i++){
            dp[1][i]=sum[i];
        }
        for(int i=2;i<=k;i++){
            for(int j=i;j<=m-k+i;j++){
                for(int k=i-1;k<j;k++){
                    if(max(dp[i-1][k],sum[j]-sum[k])<dp[i][j]){
                        dp[i][j]=max(dp[i-1][k],sum[j]-sum[k]);
                        path[i][j]=k;
                    }
                }
            }
        }
        print(k,m);
         
    //  printf("%d ",dp[k][m]);
        return 0;
    }
     
    题解思路:
      dp[i][j]指的便是i个人抄写前j本书的最短时间,dp[1][j]便是前j本书的总抄写时间(一个人抄写j本书),每一步可以从最优解dp[i-1][k]求解最优解dp[i][j],j的枚举范围为i到m-k+i,k的枚举范围为i-1到j-1,这个时候便可以用三个for循环来做,for(i:2~n){for(j:i~m-k+i){for(k:i-1~j-1)}} 每次如果max(dp[i-1][k],sum[j]-sum[k])>dp[i][j] ,赋值操作dp[i][j]=max(dp[i-1][k],sum[j]-sum[k]).最终求得的dp[k][m]即为最优解,同时用一个二维数组path[i][j]来存储路径。最终递归输出。
     
  • 相关阅读:
    上下左右固定特效
    JAVA与图形界面开发(Applet应用程序、AWT库、Swing)
    JAVA与数据库开发(JDBC-ODBC、SQL Server、MySQL)
    JAVA与网络开发(TCP:Socket、ServerSocket;UDP:DatagramSocket、DatagramPacket;多线程的C/S通讯、RMI开发概述)
    JAVA与多线程开发(线程基础、继承Thread类来定义自己的线程、实现Runnable接口来解决单继承局限性、控制多线程程并发)
    JAVA中的异常(异常处理流程、异常处理的缺陷)
    最大子段和
    最长【递增】子序列:注意没有公共,即只有一个序列。
    最长公共子序列LCS
    解编辑距离问题
  • 原文地址:https://www.cnblogs.com/cxs070998/p/11370021.html
Copyright © 2020-2023  润新知