复制书稿

题目描述

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

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

输入输出格式

输入格式

第一行两个整数m,k;(k≤m≤500)

第二行m个整数,第i个整数表示第i本书的页数。

输出格式

共k行,每行两个整数,第i行表示第i个人抄写的书的起始编号和终止编号。k行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。

输入输出样例

输入样例

9 3
1 2 3 4 5 6 7 8 9

输出样例

1 5
6 7
8 9

题解

f[i][j]表示前i个人抄j本书的最少时间
状态转移方程:f[i][j]=min{max{f[i-1][k],\(\sum_{l=k+1}^j{T_l}\),1<=k<=j-1}}
注意到题目中说要尽可能让前面的人少抄写,这里就可以采用贪心的策略,从最后一个人开始不断贪心,让其尽可能多抄写

代码

#include<cstdio>
#include<cstring>

const int MAXM=550;
int f[MAXM][MAXM],page[MAXM],sum[MAXM],m,k;

int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

inline int maxx(int x,int y){return x>y?x:y;}
inline int minn(int x,int y){return x<y?x:y;}

void dp()
{
	for(int i=2;i<=k;++i)
	{
		for(int j=1;j<=m;++j)
		{
			for(int k=1;k<=j-1;++k)
				f[i][j]=minn(f[i][j],maxx(f[i-1][k],sum[j]-sum[k]));
		}
	}
}

void print(int book,int man)
{
	if(man==0)
		return;
	if(man==1)
	{
		printf("%d %d\n",man,book);
		return;
	}
	int temp1=book,temp2=page[book];
	while(temp2+page[temp1-1]<=f[k][m])
	{
		temp2+=page[temp1-1];
		--temp1;
	}
	print(temp1-1,man-1);
	printf("%d %d\n",temp1,book);
}

int main()
{
	m=read(); k=read();
	memset(f,0x7f,sizeof(f));
	for(int i=1;i<=m;++i)
	{
		page[i]=read();
		sum[i]=sum[i-1]+page[i];
		f[1][i]=sum[i];
	}
	dp();
	print(m,k);
	return 0;
}
posted @ 2017-04-21 22:29  dustbin  阅读(778)  评论(0编辑  收藏  举报