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; }