题意:
n个队伍 每队ai个人 每张桌子有t个位置 坐在每张桌子上的人必须至少有一个同队的人 问 最少需要多少桌子
思路:
由于这题的限制只有同桌同队一个 自然想到坐的时候应该两两成组去坐 不过有些队伍可能是奇数人数 这样会分出一些3来
在考虑桌子 明显我们比较喜欢偶数座位的桌子 毕竟人在分组时候2的组比3的组常规一些 如果桌子是奇数座位 我们希望先坐下一组3人 这样座位就变成偶数了
对于偶数座位的桌子 坐的方案应该是先坐偶数个3 因为3比较不好处理让它们两两一组比较好 而且这样可以尽量坐满座位 然后坐人数为2的组 最后如果还有空 我们把3的组往里尽量插 这样最大限度的利用了桌子
对于奇数座位的桌子 如果我们没有3能让它变成偶数 那么也就是说我们现在只有2 那就浪费一个座位好了
综上YY 我们可以得出方案:
1、将人分组 这时会分出一些3 然后所有的队伍全都变成偶数人数了
2、如果桌子是奇数的 那么用刚才分出的3去将桌子变成偶数 如果3不够用 那么我们去拆队伍中的6 尽量把桌子都变成偶数(记住这里是尽量 也就是说当只有1个奇数桌子的时候 并不去拆6 因为现在队伍全是偶数 可以全分成2的组 奇数那张桌子最多也就浪费1个座位 但是如果你拆了6就会多出一个3 这样可能使使用的桌子数变多!!)
3.1、如果还有奇数的桌子 说明现在一定没有3了 那么就把2尽量放就好了
3.2、如果没有奇数的桌子 那么这时可能有3 因此对于所有的桌子(现在都是偶数) 我们采用刚才说的策略 即先偶数3再尽量2最后还有空位就插3
在方案确定后 我们只需要二分桌子数 判断这个桌子数可不可行即可
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
#define N 2010
int n, t;
int a[N], b[N];
bool yes(int m) {
int i, num3 = 0, num2 = 0, table1, table2, tablesize1, tablesize2;
if (t & 1)
table1 = m, table2 = 0, tablesize1 = t, tablesize2 = t - 3;
else
table1 = 0, table2 = m, tablesize1 = 0, tablesize2 = t;
for (i = 1; i <= n; i++) {
b[i] = a[i];
if (b[i] & 1) {
b[i] -= 3; //b all even
num3++;
}
}
if (table1) {
if (num3 >= table1) { //3 enough
num3 -= table1;
table2 = table1;
table1 = 0;
} else {
for (i = 1; i <= n; i++) { //cut 6
while (b[i] >= 6) {
b[i] -= 6;
num3 += 2;
if (num3 + 1 >= table1)
break;
}
if (num3 + 1 >= table1)
break;
}
if (num3 >= table1) {
num3 -= table1;
table2 = table1;
table1 = 0;
} else {
table1 -= num3;
table2 += num3;
num3 = 0;
}
}
}
for (i = 1; i <= n; i++)
num2 += b[i] / 2;
if (table1) {
while (table1--) {
num2 -= tablesize1 / 2;
if (num2 <= 0)
return true;
}
while (table2--) {
num2 -= tablesize2 / 2;
if (num2 <= 0)
return true;
}
} else {
int first3 = tablesize2 / 3;
int now;
if (first3 & 1)
first3--;
while (table2--) {
if (first3 <= num3) {
num3 -= first3;
now = tablesize2 - first3 * 3;
} else {
now = tablesize2 - num3 * 3;
num3 = 0;
}
int two = now / 2;
if (two <= num2) {
num2 -= two;
now -= two * 2;
} else {
now -= num2 * 2;
num2 = 0;
}
while (num3 && now >= 3) {
now -= 3;
num3--;
}
if (!num2 && !num3)
return true;
}
}
return false;
}
int main() {
int l, r, mid, ans;
scanf("%d%d", &n, &t);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
l = 0;
r = 10000000;
while (l <= r) {
mid = (l + r) >> 1;
if (yes(mid)) {
ans = mid;
r = mid - 1;
} else
l = mid + 1;
}
printf("%d\n", ans);
return 0;
}
原文地址:http://blog.csdn.net/houserabbit/article/details/40260481