题意:
给你一组数据,如:100 200 300 400 500 600 700 800 900,让你按序分成m组,使得每组的最大总和最小。
即:100 200 300 400 500 / 600 700 / 800 900
(注意每组至少要有一个数据,即100 100 100 100 100,m=4
不能分成 : / 100 100 /100 100 / 100 )
思路:
刚开始没发现上述需要注意的情况,直接二分法,后来跑出来才发现错了,最后参考了别人家的做法,贪心,从后开始标记‘/’应当出现的位置,当剩下的数据个数恰好等于剩余可分配组数时则全部标记。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 505;
long long p[N],mark[N];
int n, m;
int Judge(long long mid) {
long long sum = 0;
int cnt = m;
for (int i = 0; i < n; i++) {
sum += p[i];
if (sum > mid) {
i--;
sum = 0;
cnt--;
}
if (!cnt && i!=n-1)
return false;
}
return true;
}
int main() {
int cas;
scanf("%d", &cas);
while (cas--) {
memset(p, 0, sizeof(p));
memset(mark, 0, sizeof(mark));
scanf("%d%d", &n, &m);
long long L=0, R = 0,mid;
for (int i = 0; i < n; i++) {
scanf("%lld", &p[i]);
R += p[i];
}
while (L <= R){
mid = (L + R) / 2;
//printf("%d\t",mid);
if (Judge(mid))
R = mid - 1;
else
L = mid + 1;
}
mid = R + 1;
long long sum = 0;
int cnt = 0;
for (int i = n - 1; i > 0; i--) {
sum += p[i];
if (sum > mid) {
cnt++;
mark[i] = 1;
sum = p[i];
}
if (i + 1 == m - cnt) {
for (int j = 0; j < i; j++)
mark[j] = 1;
break;
}
}
for (int i = 0; i < n-1; i++) {
printf("%lld ", p[i]);
if (mark[i])
printf("/ ");
}
printf("%lld\n",p[n-1]);
}
return 0;
}