ZJU2002 Copying Books - 二分+贪心大败DP

题目大意:

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;
}

你可能感兴趣的:(div,books)