• P1281 书的复制 题解


    题目传送门

    暑期自己想出来的第 2 道 dp //qwq

    题目分析

    一看到题很容易想到二分答案,代码也比较简单,就不放了(其实是我没打

    因为算法标签写着是 dp 我才做这题的,那就讲讲 dp 的做法 (这题 dp 的复杂度好像比二分还高)

    目前还没有想出 O(mk) 的做法(以后也想不出),只有 O(m²k)

    f[i][j] 表示前 i 本书由 j 个人抄写的最少时间

    考虑第 j 个人,这个人的任务有 i 种情况:i、i-1—i、i-2—i......1—i

    所以就有了三重循环的算法,在枚举 i、j 里面在枚举 k(k为第 j 个人任务的起始点,最后一本是 i)

    转移方程也很简单,只有一句 

    	for (int i = 1; i <= m; i++)
    	  for (int j = 1; j <= k; j++) 
    	    for (int p = 1; p <= i; p++) 
    		  f[i][j] = min (f[i][j], max(f[p-1][j-1], s[i] - s[p-1])); 
    

    算出 f[m][k] 的最小值后统计方案就好做了

    直接用贪心,从后向前走一遍,记录每个人的任务区间

    代码

    代码也很短~~~

    #include <bits/stdc++.h>
    using namespace std;
    int m, k, a[538], s[538], f[538][538], w[538], tmp;
    int main() {
    	scanf ("%d %d", &m, &k);  tmp = k;  w[k+1] = m;
    	for (int i = 1; i <= m; i++)  scanf ("%d", a + i), s[i] = s[i-1] + a[i];
    	memset (f, 0x3f, sizeof(f));
    	for (int i = 0; i <= k; i++)  f[0][i] = 0;
    	for (int i = 1; i <= m; i++)
    	  for (int j = 1; j <= k; j++) 
    	    for (int p = 1; p <= i; p++) 
    		  f[i][j] = min (f[i][j], max(f[p-1][j-1], s[i] - s[p-1])); 
    	for (int j = m; j >= 1; j--) 
    	    if (s[w[tmp+1]] - s[j-1] > f[m][k])  w[tmp--] = j;   //记录每个人的任务端点 
    	for (int i = 1; i <= k; i++) printf ("%d %d
    ", w[i] + 1, w[i+1]);
    	return 0;
    }
    

      

  • 相关阅读:
    Defining Database and Instance【数据库与实例】
    安装rlwrap错误的问题解决方法
    ORACLE CONTROL FILE 笔记
    NTP时间服务器配置与解析
    虚拟机下Linux系统安装vmtool工具
    ORACLE clusterware组成
    ORACLE RAC集群硬件资源管理与单节点的区别
    Clusterware后台进程
    oracle数据库重建EM
    微机原理之计算机系统导论
  • 原文地址:https://www.cnblogs.com/whx666/p/11136583.html
Copyright © 2020-2023  润新知