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\n", w[i] + 1, w[i+1]);
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/whx666/p/11136583.html