zoukankan      html  css  js  c++  java
  • 书的复制记录方案DP

    题目描述

    书的复制
    现在要把maxn本有顺序的书分给n个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。

    输入
    第一行两个整数maxn, n;(n<=maxn<=100)
    第二行maxn个整数,第i个整数表示第i本书的页数。
    输出
    共n行,每行两个正整数,第i行表示第i个人抄写的书的起始编号和终止编号。n行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。

    此题记录方案不同于一般DP,一般DP,按正常维护过程中记录一些量即可,但此题不可以,

    因为方案要求是,抄尽可能少的页数,在此基础上,靠前的尽可能少抄,会发现,普通正序循环,在满足第一问的前提下,第二问不具有最优子结构,举个例子,输入:

    10   4

    1 1 1 1 1 1 1 1 1 1

    最优情况最多的人三页,四个人抄写的页数分别为:1,3,3,3;

    按照普通状态定义,f[i,j]表示前i个人抄j本书,抄的最多的抄多少,在维护f的过程中

    维护一个ans[i,j],记录到达(i,j)这个状态,f最小的情况下,第i个人所拿的书是第几本开始(即第i个人拿第ans【i,j】到第j本书)

    像普通DP一样,f更新一次,ans就更新一次,但这样会出问题

    比如ans[2,4]=3,因为此时的最优情况就是第三个人拿后两本(f[2,4]=2一人两本),

    这样在DP完之后,按路径把ans输出去,会出问题,因为此时还不知道后面人会怎么办

    代码见下(不可AC):

    program sky;
    var
      i,j,k,m,n,tp:longint;
      a,g:array[0..101] of longint;
      f,ans:array[0..101,0..1001] of longint;
      print:array[0..101] of longint;
    function max(qq,ww:longint):longint;
    begin
      if qq>ww then exit(qq); exit(ww);
    end;
    begin
      assign(input,'book.in'); reset(input);
      assign(output,'book.out'); rewrite(output);
      readln(m,n);
      for i:=1 to m do begin read(a[i]); g[i]:=g[i-1]+a[i]; end;
      fillchar(f,sizeof(f),63);
      f[0,0]:=0;
      for i:=1 to n do
        for j:=0 to m do
          for k:=0 to j do
          begin
            tp:=max(f[i-1,k],g[j]-g[k]);
            if f[i,j]>tp then
            begin
              f[i,j]:=tp;
              ans[i,j]:=k+1;
            end;
          end;
      while j<>0 do
      begin
        print[i]:=ans[i,j];
        j:=ans[i,j]-1; dec(i);
      end;
      writeln(f[4,10]);
      if n<>0 then writeln(1,' ',print[2]-1);
      for i:=2 to n-1 do writeln(print[i],' ',print[i+1]-1);
      if n<>0 then writeln(print[n],' ',m);
      close(input); close(output);
    end.

    所以……我采用了一个比较朴素的办法,就是得到f之后,模拟装书……模拟部分码量大于DP,在此不再给出……不过网上也有直接DP记录方案的,状态表示需要稍作调整,本文重点在于指出,直接按上述状态记录方案,有可能会写出有后效性的代码,分享一下经验

    
    

     

    希望大家参考一下bright的博客,但和直接模拟输出的结果是不一样的,在我手中的数据证明是bright的有误,他是直接DP记录方案的,希望众多神牛看出端倪,不管哪种解法有误,都提出来共同进步,蒟蒻代码如下:

    program sky;
    var
      a,g,p:array[0..10000] of longint;
      f:array[0..101,0..1001] of longint;
      tot,i,j,k,m,n,ans,tp:longint;
    function min(qq,ww:longint):longint;
    begin
      if qq>ww then exit(ww); exit(qq);
    end;
    function max(qq,ww:longint):longint;
    begin
      if qq>ww then exit(qq); exit(ww);
    end;
    begin
      assign(input,'book.in'); reset(input);
      assign(output,'book.out'); rewrite(output);
      readln(m,n);
      for i:=1 to m do begin read(a[i]); g[i]:=g[i-1]+a[i]; end;
      fillchar(f,sizeof(f),63); f[0,0]:=0;
      for i:=1 to n do
        for j:=i to m do
          for k:=0 to j-1 do
            f[i,j]:=min(f[i,j],max(f[i-1,k],g[j]-g[k]));
      ans:=f[n,m];
      tot:=n;
      for i:=m downto 1 do
      begin
        if tp+a[i]>ans then
        begin
          p[tot]:=i+1;
          dec(tot);
          tp:=a[i];
        end else inc(tp,a[i]);
      end;
      p[n+1]:=m+1;
      if (n<>0) then writeln(1,' ',p[2]-1);
      for i:=2 to n do writeln(p[i],' ',p[i+1]-1);
      close(input); close(output);
    end.
  • 相关阅读:
    WebClient 非阻塞客户端 RestTemplate 阻塞式客户端
    微服务网关---调用其他微服务
    复习下comparable和comparator以及比较
    关于InitializingBean的用法、应用
    Scheduled(cron = "")
    windows查看进程方法(老是忘只能写了)
    vue 控件component
    vue 过滤器的使用实例
    vue基础
    日志脱敏工具
  • 原文地址:https://www.cnblogs.com/skysun/p/2508053.html
Copyright © 2011-2022 走看看