书的复制

Description

现在要把m本有顺序的书分给k个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。

现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。

Analysis

对于i本书分给j个人分析,枚举第j个人分到的本数k,dp[i][j]=max(dp[i-k][j-1],treat(i-k+1,i))。treat(i,j)函数用于处理第i到j本书给一个人抄写的时间。

动规可行性判断:

  • 最优子结构:前i-k人抄写页数最大值当然越小越优。
  • 无后效性:前面的抄写方式不会影响之后的分配。
dp[i][j]=min(dp[i][j],max(dp[i-k][j-1],treat(i-k+1,i)))

当然这题到这里还没有结束...在算出抄写最小值后还要输出路径,输出路径有两种方式:

  1. 在状态转移时进行标记
  2. 算出最小值后贪心出解

一开始用方案1,为每次转移中的最优方案标上mark[i][j],最后递归输出。因为条件:
复制时间为抄写页数最多的人用去的时间, 调了半天也没调对。

那么只能用贪心出解了,从最后一人开始循环,在范围允许内,能抄多少本抄多少本。

Code

#include <bits/stdc++.h>

int n,m,p[501],sum[501],dp[501][501],end[501];

int main()
{
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    std::cin>>n>>m;
    for(int i=1;i<=n;i++)
        std::cin>>p[i],sum[i]=sum[i-1]+p[i];
    memset(dp,0x3f,sizeof(dp));
    for(int i=0;i<=m;i++)
        dp[0][i]=0;
    for(int i=0;i<=n;i++)
    for(int j=1;j<=m;j++)
    for(int k=0;k<=i;k++)
        dp[i][j]=std::min(dp[i][j],std::max(dp[i-k][j-1],sum[i]-sum[i-k]));
    for(int i=m,sub=n;i>=1&&sub;i--)
    {
        int rec=0;
        end[i]=sub;
        while(rec<=dp[n][m]&&sub)
            rec+=p[sub--];
        if(rec>dp[n][m])sub++;
    }
    for(int i=1;i<=m;i++)
        if(!end[i])
            std::cout<<"0 "<<end[i]<<std::endl;
        else
            std::cout<<end[i-1]+1<<" "<<end[i]<<std::endl;
    return 0;
}

转载于:https://www.cnblogs.com/qswx/p/9492449.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值