书的复制【DP】

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


> Input
第一行两个整数,m,k(k<=m<=500)
第二行为m个整数,第i个数表示第i本书的页数。

>Output
最短时间


>Sample Input
9 3
1 2 3 4 5 6 7 8 9

>Sample Output
17


> 解题思路
其实这一道DP还是挺简单的,就是要注意的是每一本书只能交给一个人来抄,而且一个人抄的书们必须是连续的,这样来说这一道题就有一点儿像乘积最大了,不,是十分的像。
还要明白的是:一列(堆)数(书),在被分配完后,它所花的时间是这些分成一段一段后,总数最大的一个数。

f[i][j]所表示的是前i个数用j个人来做的最小时间。
所以。
状态转移方程:

f[i][j]=min(max(f[t][j-1],s[i]-s[t]),f[i][j])

用t来划分,前t个数用j-1个人,剩下的全部一个人来做。
s为前缀和,max是为了求出时间,上面解释过,min就更不用解释了吧,求最小的一个数。


>代码

#include<iostream>
#include<cstdio>
using namespace std;
const int inf=10000000;
int m,k,s[505],f[505][505];
int main()
{
	scanf("%d%d",&m,&k);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&s[i]); s[i]+=s[i-1]; //前缀和
		f[i][1]=s[i];//设初值
	}
	for(int i=2;i<=m;i++) //前i个数
	 for(int j=2;j<=k;j++) //用j个人(1个人的设置过了,就不用再循环了)
	 {
	 	f[i][j]=inf;
	 	for(int t=j-1;t<i;t++)
	     f[i][j]=min(max(f[t][j-1],s[i]-s[t]),f[i][j]);
	 }
	printf("%d",f[m][k]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/85014591
今日推荐