略蛋疼的一道题目,研究了好久,最开始简单的枚举回溯法,果断超时。网上看到了好多人的优化,最后选择了一种线性的解法,只需扫描一遍即可。
基本思路:将问题转化为依次往板上放包裹,为了让板尽可能的平衡,一定是先放扭矩小的上去,所以先将包裹分类,左支点左边的一波,中间的一波,右支点右边的一波,分别排序,把中间的一波先放上去,这样可以增加系统的稳定性,然后左右两边依次往上放直到一边失去平衡,换另一边上,如果两边都不能放还有剩余的话,就是没有解了。
思路参考:
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; }