首页 > 试题广场 >

画匠问题

[编程题]画匠问题
  • 热度指数:1100 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个整型数组arr, 数组中的每个值都为正数,表示完成一幅画作需要的时间,再给定一个整数num,表示画匠的数量,每个画匠只能画连在一起(即数组内连续的一段)的画作。所有画家并行工作,请返回完成所有的画作的最少时间。
[要求]
时间复杂度为(其中S表示所有画作所需时间的和)

输入描述:
第一行两个整数N, K表示数组大小,画匠的数量。
接下来一行N个整数表示完成每幅画作所需要的时间。


输出描述:
输出一个整数表示答案
示例1

输入

3 2
3 1 4

输出

4

说明

最好的分配方式为第一个画匠画3和1,所需时间为4,第二个画匠画4,所需时间为4。因为并行工作,所以最少时间为4,如果分配方式为第一个画匠画3,所需时间为3,第二个画匠画1和4,所需的时间为5,那么最少时间为5,显然没有第一种分配方式好,所以返回4
示例2

输入

5 3
1 1 1 4 3

输出

4

说明

最好的分配方式为第一个画匠画前三个1,所需时间为3,第二个画匠画4,所需时间为4,第三个画匠画3,所需时间为3,返回4
示例3

输入

5 2
99 82 44 35 3

输出

164

说明

[99] [82 44 35 3]

备注:

二分法,限制所有画作完成的时长,然后检查在这个时长限制下画家的数量够不够。够的话说明时间还可以压缩,不够的话就要放宽时长限制,多给一些时间。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] params = br.readLine().split(" ");
        int n = Integer.parseInt(params[0]), k = Integer.parseInt(params[1]);
        params = br.readLine().split(" ");
        int[] time = new int[n];
        long lb = 0, ub = 0;      // 二分的边界
        for(int i = 0; i < n; i++) {
            time[i] = Integer.parseInt(params[i]);
            lb = Math.max(time[i], lb);
            ub += time[i];
        }
        while(lb < ub){
            long h = lb + ((ub - lb) >> 1);     // 花费h小时
            if(getPainterNums(h, time) <= k)
                ub = h;          // 限制在h小时,只需要不超过k个画家就能做到,可以压缩上界
            else
                lb = h + 1;
        }
        System.out.println(ub);
    }
    
    // 计算h小时完成所有画作需要的画家数
    private static int getPainterNums(long h, int[] time) {
        long partTime = 0;
        int parts = 1;
        for(int i = 0; i < time.length; i++){
            if(partTime + time[i] <= h){
                partTime += time[i];      // 这一部分凑h的时长
            }else{
                partTime = time[i];       // 超过h的时长,需要加一位画家
                parts ++;
            }
        }
        return parts;
    }
}

发表于 2021-11-17 23:17:29 回复(0)
#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main(){
    int n, k;
    cin>>n>>k;
    ll a[n+1], x, Max=0;
    for(int i=0;i<n;i++){
        cin>>a[i];
        Max = max(Max, a[i]);
    }
    ll l = Max, r = INT64_MAX>>2, m, s, cnt;
    while(l<r){
        s = cnt = 0;
        m = (l+r)>>1;
        for(int i=0;i<n;i++){
            if(m < s+a[i]){
                s = a[i];
                cnt++;
            }else
                s += a[i];
        }
        if(s)
            cnt++;
        if(cnt > k)
            l = m+1;
        else
            r = m;
    }
    cout<<l<<endl;
    return 0;
}

编辑于 2020-04-19 02:00:59 回复(2)
def solution(arr, num):  # 工作清单和工人数目 | O(N*logS), S=sum(arr)
    assert arr and len(arr) and num
    if len(arr) <= num:  # 如果工人过多,则是取最长的一个工作返回
        return max(arr)

    def get_need_num(limit):  # 每个画师只能工作不超过limit的时间,问需要几个画师才能完成
        res, worked = 1, 0  # 已用画师数目, 当前画师已工作时间
        for v in arr:
            if v > limit:  # 这一幅画哪怕单独分配给一个画师也完成不了
                return float('inf')
            worked += v
            if worked > limit:  # 如果尝试画当前的画已超工时
                res += 1  # 新增一个画师来画这幅画
                worked = v  # 新增画师的当前工时为v
        return res

    min_sum, max_sum = 0, sum(arr)  # 二分法确定每个画师的最大工作量
    while min_sum != max_sum - 1:
        mid = (min_sum + max_sum) // 2
        if get_need_num(mid) > num:
            min_sum = mid
        else:
            max_sum = mid
    return max_sum

n, num = map(int, input().split())
arrs = list(map(int, input().split()))
print(solution(arrs, num))

发表于 2020-06-26 12:01:30 回复(0)