1. 程式人生 > >UVA(714) Copying Books

UVA(714) Copying Books

最大值最小化應該是二分法中經典的題目,Copying Books就是一道最大值最小化的題目

題目大致的意思是要抄N本書,編號為1,2,3...N, 每本書有1<=x<=10000000頁, 把這些書分配給K個抄寫員,要求分配給某個抄寫員的那些書的編號必須是連續的。每個抄寫員的速度是相同的,求所有書抄完所用的最少時間的分配方案。

設序列的最大值為max,總的和為sum。很顯然序列的最大值在[max,sum]之間,找到了上界和下界就可以二分查詢。在每次查詢的時候,我們可以儘量向右劃分,這樣可以使劃分的最大值儘量最小。如果小於等於查詢的數,r = mid,反之 i = mid + 1。找到了最大值中的最小值之後就可以進行劃分,劃分時只要反向遍歷陣列,將每個區間儘量向左劃即可。不過要注意用 資料過大,要用long long儲存,否則會溢位。

題目可以在UVA上提交,不過UVA測評的速度太慢了,可以在https://vjudge.net這個網站上提交。下面是AC的程式碼。

#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include<algorithm>
#include<memory>
#include<limits.h>
using namespace std;
int n,k,m;
int arr[501],ans[501];
int findMid(long long num)
{
    long long sum = 0,count1 = 0;
    for(int i = 0;i < m;++i)
    {
        if(count1 > k - 1)
            return 0;
        sum += arr[i];
        if(sum > num)
        {
            sum = arr[i];
            ++count1;
        }

    }
    if(count1 > k - 1)
        return 0;
    return 1;
}
void divid(long long num)
{
    long long sum = 0,count1 = 0;
    for(int i = m - 1;i >= 0;--i)
        if(sum + arr[i] > num)
        {
            ans[i + 1] = 1;
            sum = arr[i];
            count1++;
        }
        else
            sum += arr[i];
    int i = 1;
    while(i < m && count1 < k - 1)
    {
        if(!ans[i])
            ans[i] = count1++;
        ++i;
    }
}
int main()
{
    cin >> n;
    while(n)
    {
        memset(arr,0,sizeof(arr));
        memset(ans,0,sizeof(ans));
        long long sum = 0;
        int max1 = INT_MIN;
        cin >> m >> k;
        for(int i = 0;i < m;++i)
        {
            cin >> arr[i];
            sum += arr[i];
            max1 = max(max1,arr[i]);
        }
        long long i = max1,j = sum + 1,mid;
        while(i < j)
        {
            mid = (i + j) / 2;
            if(findMid(mid))
                j = mid;
            else
                i = mid + 1;
        }
        divid(i);
        for(int i = 0;i < m - 1;++i)
        {
            if(ans[i])
                cout << '/' << ' ';
            cout << arr[i] << ' ';
        }
        if(ans[m - 1])
            cout << '/' << ' ';
        cout << arr[m - 1] << endl;
        --n;
    }
	return 0;
}