题目大意:
m本书分给k个抄书员,书的页数为p1,p2...pm。每个抄书员速度相同,只能分得连续的若干本书。求一种分配方案使得分得所用总时间最少。每个抄书员分配至少一本书。
解题思路:
此题是一个典型的动态规划的题目。上半年集训的时候听野马讲过这个题,使用二分+贪心可以非常高效的解决。DP的时间复杂度是O(m^2),二分+贪心的复杂度是O(m*logn),n是书的总页数。
二分的思路是这样:首先确定抄书员分得的最多的页数min=max{ pi } ,max=∑pi。取mid=(max+min)/2,使用贪心的方法给每个抄书员分配连续不超过mid页的书,尽可能多地分配。若能成功,则使max=mid;否则min=miid+1。直到min==max时,得到抄书员分配书最佳方案为min或max。
处理时注意要打印具体方案,注意处理“每个抄书员分配至少一本书”。
附代码:
/*
ZJU2002 Copying Books
*/
#include <stdio.h>
#define N 501
int assignbook(int p[],int m,int k,int mid,int f[])
{
int i,j,s;
int e[N]={0};
int flag=0;
i=m-1;j=0;
while(i>=0)
{
s=0;j++;
if(j>k) return 0;
e[i]=1;
while(i>=0)
{
if(s+p[i]>mid) break;
s+=p[i--];
if(k-j==i+1) /****/
{
while(i>=0) e[i--]=1;
flag=1; break;
}
}
if(flag) break;
}
for(i=0;i<m;i++) f[i]=e[i];
return 1;
}
int main()
{
int i,j,k,m,n;
int T;
scanf("%d",&T);
while(T--)
{
int p[N]={0};
int e[N]={0};
int flag;
long long max,min,mid;
//input
scanf("%d%d",&m,&k);
max=0; min=0;
for(i=0;i<m;i++) scanf("%d",&p[i]),max+=p[i],min=(min>p[i]?min:p[i]);
//binary div
while(min<max)
{
mid=(max+min)/2;
if(assignbook(p,m,k,mid,e))
max=mid;
else
min=mid+1;
}
//output
//printf("mid=%I64d/n",max);
for(i=0;i<m-1;i++)
{
printf("%d ",p[i]);
if(e[i]) printf("/ ");
}
printf("%d/n",p[m-1]);
}
//system("pause");
return 0;
}