略蛋疼的一道题目,研究了好久,最开始简单的枚举回溯法,果断超时。网上看到了好多人的优化,最后选择了一种线性的解法,只需扫描一遍即可。
基本思路:将问题转化为依次往板上放包裹,为了让板尽可能的平衡,一定是先放扭矩小的上去,所以先将包裹分类,左支点左边的一波,中间的一波,右支点右边的一波,分别排序,把中间的一波先放上去,这样可以增加系统的稳定性,然后左右两边依次往上放直到一边失去平衡,换另一边上,如果两边都不能放还有剩余的话,就是没有解了。
思路参考:
http://www.ngszone.com/blog/archives/250
0.019s AC:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
int len;
int wei;
int n;
typedef struct Pack {
int x;
int w;
int torque;
} Pack;
Pack left[25];
Pack right[25];
Pack mid[25];
Pack all[25];
int lenL = 0, lenR = 0, lenM = 0, lenA = 0;
int isBalanced(int idx) {
double weiLeftA = 0;
double weiRightA = 0;
double weiLeftB = 0;
double weiRightB = 0;
weiLeftA += 0.5 * (0.5 * len - 1.5) * (0.5 * len - 1.5) * wei / len;
weiRightA += 0.5 * (0.5 * len + 1.5) * (0.5 * len + 1.5) * wei / len;
weiLeftB += 0.5 * (0.5 * len + 1.5) * (0.5 * len + 1.5) * wei / len;
weiRightB += 0.5 * (0.5 * len - 1.5) * (0.5 * len - 1.5) * wei / len;
int i;
for (i = 0; i < idx; i++) {
if (all[i].x < -1.5)
weiLeftA += (-1.5 - all[i].x) * all[i].w;
if (all[i].x > -1.5)
weiRightA += (all[i].x + 1.5) * all[i].w;
if (all[i].x < 1.5)
weiLeftB += (1.5 - all[i].x) * all[i].w;
if (all[i].x > 1.5)
weiRightB += (all[i].x - 1.5) * all[i].w;
}
if (weiLeftA > weiRightA)
return 0;
if (weiLeftB < weiRightB)
return 0;
return 1;
}
int cmp(const void*a, const void*b) {
Pack *aa = (Pack*) a;
Pack *bb = (Pack*) b;
return aa->torque - bb->torque;
}
int main() {
int cases = 1;
while (scanf("%d%d%d", &len, &wei, &n)) {
if (len == 0)
break;
lenL = lenR = lenM = lenA = 0;
int i;
int tmpX, tmpW;
for (i = 0; i < n; i++) {
scanf("%d%d", &tmpX, &tmpW);
all[lenA].x = tmpX;
all[lenA].w = tmpW;
lenA++;
if (tmpX < -1.5) {
left[lenL].x = tmpX;
left[lenL].w = tmpW;
left[lenL].torque = abs(tmpX * tmpW);
lenL++;
} else if (tmpX > 1.5) {
right[lenR].x = tmpX;
right[lenR].w = tmpW;
right[lenR].torque = abs(tmpX * tmpW);
lenR++;
} else {
mid[lenM].x = tmpX;
mid[lenM].w = tmpW;
mid[lenM].torque = abs(tmpX * tmpW);
lenM++;
}
}
printf("Case %d:\n", cases++);
if (!isBalanced(lenA)) {
printf("Impossible\n");
continue;
}
qsort(left, lenL, sizeof(Pack), cmp);
qsort(mid, lenM, sizeof(Pack), cmp);
qsort(right, lenR, sizeof(Pack), cmp);
int l = 0, m = 0, r = 0, a = 0;
int f1 = 0;
int f2 = 0;
int impossible = 0;
while (m < lenM) {
memcpy(&all[a++], &mid[m++], sizeof(Pack));
}
while (a < lenA) {
while (l < lenL) {
memcpy(&all[a++], &left[l++], sizeof(Pack));
if (!isBalanced(a)) {
a--;
l--;
f1 = 1;
break;
} else {
f2 = 0;
}
}
while (r < lenR) {
memcpy(&all[a++], &right[r++], sizeof(Pack));
if (!isBalanced(a)) {
a--;
r--;
f2 = 1;
break;
} else {
f1 = 0;
}
}
if (f1 && f2) {
impossible = 1;
break;
}
}
if (impossible)
printf("Impossible\n");
else {
for (i = lenA - 1; i >= 0; i--)
printf("%d %d\n", all[i].x, all[i].w);
}
}
return 0;
}
枚举回溯超时的代码:
#include<stdio.h>
#include<string.h>
int len;
int wei;
int n;
int pac[25][2];
int removed[25];
int a[25];
int solved;
int isBalanced() {
int weiLeft = 0;
int weiRight = 0;
weiLeft += 0.5 * (0.5 * len - 1.5) * (0.5 * len - 1.5) * wei / len;
weiRight += 0.5 * (0.5 * len + 1.5) * (0.5 * len + 1.5) * wei / len;
int i;
for (i = 0; i < n; i++) {
if (removed[i])
continue;
if (pac[i][0] < -1.5) {
weiLeft += (pac[i][0] * (-1) - 1.5) * pac[i][1];
}
if (pac[i][0] > -1.5) {
weiRight += (pac[i][0] + 1.5) * pac[i][1];
}
}
if (weiLeft > weiRight)
return 0;
weiLeft = 0;
weiRight = 0;
weiLeft += 0.5 * (0.5 * len + 1.5) * (0.5 * len + 1.5) * wei / len;
weiRight += 0.5 * (0.5 * len - 1.5) * (0.5 * len - 1.5) * wei / len;
for (i = 0; i < n; i++) {
if (removed[i])
continue;
if (pac[i][0] > 1.5) {
weiRight += (pac[i][0] - 1.5) * pac[i][1];
}
if (pac[i][0] < 1.5) {
weiLeft += (1.5 - pac[i][0]) * pac[i][1];
}
}
if (weiRight > weiLeft)
return 0;
return 1;
}
void removePac(int cur) {
if (solved)
return;
if (cur == n) {
solved = 1;
int i;
for (i = 0; i < n; i++) {
printf("%d,%d\n", pac[a[i]][0], pac[a[i]][1]);
}
} else {
int i;
for (i = 0; i < n; i++) {
int j;
int ok = 1;
for (j = 0; j < cur; j++) {
if (a[j] == i) {
ok = 0;
break;
}
}
if (ok) {
if (!isBalanced())
return;
a[cur] = i;
removed[i] = 1;
removePac(cur + 1);
removed[i] = 0;
}
}
}
return;
}
int main() {
int cases = 1;
while (scanf("%d%d%d", &len, &wei, &n)) {
if (len == 0)
break;
memset(removed, 0, sizeof(removed));
solved = 0;
int i;
for (i = 0; i < n; i++) {
scanf("%d%d", &pac[i][0], &pac[i][1]);
}
printf("Case %d:\n", cases++);
removePac(0);
if (!solved)
printf("Impossible\n");
}
return 0;
}