题目大意:在一块长L重量M的木板上放n个木块,下n行表示木块放的位置和木块的重量,开始木板是处于平衡的,每次拿下一个木块,直到木块全部被取下,期间要求木板不发生偏移,如果可以完全取下,就输出去下木块的顺序(情况不唯一),不能完全取下就输出Impossible。
解题思路:
<1>可以将木块取下的问题看成是将木块放上木板。
<2>要分清楚什么时候木板会倾斜,因为它有两个支点,所以要考虑两种情况,(wl1:-L ~ 1.5 ,wr1:1.5 ~ L 和 wl2:-L ~ -1.5 , wr2:-1.5 ~ L),要注意的是wl1 和 wr2 下面还有一个支点,所以 wl1 > wr1 和 wr2 > wl2 的时候木板是不会发生偏移的。(这里提一下,F = L * W , 对于质量均匀的木盘呢,L取长度的中间值)
<3>接下来要讲点关键的优化了,在计算完原先木板的力矩之后呢, 可以将处于(-1.5~1.5)这个区域的木块放到木板上,不难发现,这个地方的木块只会加大木板的稳定度(对应实际问题就是最后拿下来)。
<4>第二个优化就是该解决掉那部分会导致木块发生移动的木块了,首先将木块按位置分成放左边和放右边的两份,为什么要分开来考虑呢,因为同堆的木块对木板的偏移趋势是相同的,这对有助于后面用到的贪心的方法,只需将所有木块遍历一遍就可以的到结果。
<5>将两堆木块中的木块分别按照力矩的大小从小到大排列,然后从任意一堆中每次取小的放入木板,直到下一个木块放入后会发生移动,然后就换放另一堆的木块,同样的终止条件,直到木块全部放上去为止,这中间有个终止的特殊条件,就是不能全部放上去的情况,对应的就是两堆木块均无法放入的情况。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
int cnt[3], cur[3];
double wl1, wr1, wl2, wr2;
struct Block {
int pos;
int w;
} block[3][30], record[30], x;
int cmp(const void *c, const void *d) {
Block *a = (Block *)c;
Block *b = (Block *)d;
return abs(a->pos * a->w) > abs(b->pos * b->w);
}
int DFS(int dir, bool real) {
int ok = false;
for (int i = cur[dir]; i < cnt[dir]; i++) {
if (dir == 0) {
if (wr1 < wl1 + (-3 - block[dir][i].pos) * block[dir][i].w)
break;
wl1 += (-3 - block[dir][i].pos) * block[dir][i].w;
wl2 += ( 3 - block[dir][i].pos) * block[dir][i].w;
}
else {
if (wl2 < wr2 + (block[dir][i].pos - 3) * block[dir][i].w)
break;
wr2 += (block[dir][i].pos - 3) * block[dir][i].w;
wr1 += (block[dir][i].pos + 3) * block[dir][i].w;
}
ok = true;
record[cnt[1]] = block[dir][i];
cur[dir]++;
cnt[1]++;
}
if (ok || real)
DFS (2 - dir, false);
}
int main() {
int l, m, n, t = 0;
while (scanf("%d%d%d", &l, &m, &n), l) {
//初始化
memset(block, 0, sizeof(block));
memset(cnt, 0, sizeof(cnt));
memset(cur, 0, sizeof(cur));
wl1 = wr2 = (l - 3) * (l - 3) * m / (l * 4.0);
wr1 = wl2 = (l + 3)* (l + 3) * m / (l * 4.0);
//读入数据
for (int i = 0; i < n; i++) {
scanf("%d%d", &x.pos, &x.w);
x.pos *= 2;
if (x.pos > 3)
block[2][cnt[2]++] = x;
else if (x.pos < -3)
block[0][cnt[0]++] = x;
else
block[1][cnt[1]++] = x;
}
//处理数据
for (int i = 0; i < 3; i++)
qsort(block[i], cnt[i], sizeof(block[0][0]), cmp);
memcpy(record, block[1], sizeof(block[1]));
for (int i = 0; i < cnt[1]; i++) {
wr1 += (block[1][i].pos + 3) * block[1][i].w;
wl2 += (3 - block[1][i].pos) * block[1][i].w;
}
DFS(0, true);
//输出结果
printf("Case %d:\n", ++t);
if (cnt[1] == n)
for (int i = n - 1; i >= 0; i--)
printf("%d %d\n", record[i].pos / 2, record[i].w);
else
printf("Impossible\n");
}
return 0;
}