1. 程式人生 > >UVa 714 Copying Books 二分 + 貪心 (最大值最小化問題)

UVa 714 Copying Books 二分 + 貪心 (最大值最小化問題)

/**
*  最大值最小化問題: 二分法。  劉汝佳那本白書上也說的很詳細。
*     先把最大值的可能區間計算出來,也就是[0, maxAns] maxAns 就是所有頁數總和。
*  然後再在答案區間裡先把“最大值最小化”。
*     得到最小化後的最大值以後,就可以根據這個最大值來對最終答案進行計算。
*  如何分割槽,也就是計算最後答案ans:  這裡就要用到貪心思想,因為題目要求
*  如果有多種可能情況,讓區間集合所含的元素數從小到大排列。這樣就可以貪心地
*  從所有pages的最後一個元素往前遍歷來進行劃分區間,只要其總和不大於之前所求的最大值,
*  就歸到那個區間。
*     在把所有區間分好後,還有個情況就是,這個時候可能需要3個斜槓來分4個區間,
*  然而只用了2個(比如樣例2),這樣還有一個斜槓沒用到,就再用貪心,把pages從第一個開始往後掃,
*  如果當前pages不用劃斜槓,而剩餘斜槓數大於0,則在這裡添個斜槓。
*/

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#define INF 0x7fffffff
#define MAXS 501
#define LL long long
using namespace std;
int m, k;
LL maxAns;
int pages[MAXS], ans[MAXS];

bool judge(LL x) {
    int sum = 0, t = k;
    for(int i = 0; i < m; i ++) {
        sum += pages[i];
        if(sum > x) {
            i --;
            sum = 0;
            t --;
        }
        if(!t) {
            if(i != m - 1) return false;
            else return true;
        }
    }
    return true;
}

void solve() {
    memset(ans, 0, sizeof(ans));
    LL l, r, cur;
    l = 0; r = maxAns;
    while(l < r) {
        cur = (l + r) / 2;
        if(judge(cur))   r = cur;
        else             l = cur + 1;
    }
    int sum = 0;
    for(int i = m - 1; i >= 0; i --) {
        sum += pages[i];
        if(sum > r) {
            sum = 0;
            ans[++ i] = 1;
            k --;
        }
    }
    int i = 1;
    while(k > 1) {
        for(; i < m; i ++ ) {
            if(!ans[i]) {
                ans[i] = 1;
                k --;
                break;
            }
        }
    }
    printf("%d", pages[0]);
    for(int i = 1; i < m; i ++) {
        if(ans[i]) printf(" /");
        printf(" %d", pages[i]);
    }
    printf("\n");
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t --) {
        maxAns = 0;
        scanf("%d%d", &m, &k);
        for(int i = 0; i < m; i ++) {
            scanf("%d", &pages[i]);
            maxAns += pages[i];
        }
        solve();
    }
    return 0;
}