uva 714 Copying Books

Thinking about it:

  看完这题的时候,确实没有啥思路,看了题解才明白的。这个最小值是通过二分法先确定下来的,然后才能分组。这种思维方式超出了我的意料,我还一直朝着DP的思路走。看来我还需要多磨练。

 

Reference:

  《算法竞赛入门经典(第2版)》

 

Code:  

/**
 * AC @ Sep 5 th 2015
 * Run Time : 0.000s
 */
#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int MAXN = 500 + 50;
int value[MAXN];
int M, K;
LL sum, maxC;

void read() {
    cin >> M >> K;
    sum = maxC = 0;
    for (int i = 0; i < M; ++i) {
        cin >> value[i];
        sum += value[i];
        maxC = maxC > value[i] ? maxC : value[i];
    }
}

bool is_possile(int p) {
    int tmpValue = 0, group = 1;
    for (int i = M-1; i >= 0; --i) {
        if (tmpValue + value[i] > p || i+1 <= K - group) {
            tmpValue = value[i];
            group ++;
        } else {
            tmpValue += value[i];
        }
    }
    return group == K;
}

void print(int pos, int group, int p) {
    std::vector<int> v;
    int i;
    LL sum = 0;
    for (i = pos; sum + value[i] <= p && i+1>K-group; --i) {
        sum += value[i];
        v.push_back(value[i]);
    }
    if (group == K) { // the head
        for (int l = v.size()-1; l > 0; --l) {
            cout << v[l] << " ";
        }
        cout << v[0];
    } else {
        print(i, group+1, p);
        cout << " /";
        for (int l = v.size()-1; l >= 0; --l) {
            cout << " " << v[l];
        }
    }
}

void output(int p) {
    print(M-1, 1, p);
    cout << endl;
}

void work() {
    // if left is initialized with 0, some problems will occur
    LL left = maxC, right = sum, mid;
    while (right > left) {
        mid = (right + left) >> 1;
        if (is_possile(mid)) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    output(right);
}

int main(int argc, char const *argv[]) {
    ios::sync_with_stdio(false);        
    cin.tie(0);
    int T;
    cin >> T;
    while (T --) {
        read();
        work();
    }
    return 0;
}

  

posted @ 2015-09-06 12:41 Emerald 阅读(...) 评论(...) 编辑 收藏