【二分与三分03】Copying Books

本文介绍了一种使用二分法和贪心策略解决书本分配问题的方法。目标是将一系列页数不同的书分配给多个抄写员,使得整体抄写时间最短。通过设定抄写员能承担的最大页数范围,并采用从后向前的分组策略实现最优解。

题目来源:


题目大意:

将n本页数为p1,p2,……,pm(顺序排列)的书分给k个抄写员抄写,每个抄写员速度一样且每个抄写员只能抄写编号相邻的书,求抄写时间最少的分组。


解题思路:

二分法与贪心。

通过二分法求出一个抄写员最多需要抄写的页数,然后按照这个页数来分组,前面的组尽量分得多一点。

初始下界和上界是最后一本书的页数和所有书的总页数。

分组标记的时候从后往前找,之后还要检查分完了没,没分完就继续直到分完。

试过从前面开始找但总是出错放弃了x


AC代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define N 510
int n, k;
int c[N];

int check(long long mid)
{
    int i, j;
    long long num = 0;
    f = 0;
    for (i=0,j=0;i<n;i++)
    {
        num += c[i];
        if (num>mid)
        {
            j++;
            i--;
            num = 0;
        }
        if (j==k)
        {
            if (i!=n-1)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        }
    }
    return 1;
}

long long apart(long long l, long long r)
{
    long long mid;
    while (l<r)
    {
        mid = (l+r)/2;
        if (check(mid))
        {
            r = mid;
        }
        else
        {
            l = mid + 1;
        }
    }
    return r;
}

void print(long long r)
{
    int flag[N] = {0};
    int i, x=k;
    long long sum = 0;
    for (i=n-1;i>=0;i--)
    {
        sum += c[i];
        if (sum>r)
        {
            i++;
            flag[i] = 1;
            x--;
            sum = 0;
        }
    }
    while (x>1)
    {
        for (i=1;i<n;i++)
        {
            if (!flag[i])
            {
                flag[i] = 1;
                x--;
                break;
            }
        }
    }
    for (i=0;i<n;i++)
    {
        if (flag[i])
        {
            printf("/ ");
        }
        printf("%d%c",c[i],i==n-1 ? '\n':' ');
    }
}

int main()
{
    int T, i;
    long long sum, min;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&k);
        sum = 0;
        for (i=0;i<n;i++)
        {
            scanf("%d",&c[i]);
            sum += c[i];
        }
        min = c[i-1];
        print(apart(min,sum));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值