UVA 10123 No Tipping

来源:互联网 发布:人工智能三大定律 编辑:程序博客网 时间:2024/05/16 03:09

分析

这是一双支点的杠杆的题目,问初始时,依次有选择地拿去杠杆上的有质量的物块后,杠杆是否平衡。给出选择。

杠杆如何平衡?
因为有两个支点,对于任一支点,如果左右两侧物块的力矩和相等,则杠杆平衡,若两支点均不能满足则杠杆失衡。
需要注意的是,因为杠杆本身具有重量,比如以右侧支点研究对象,那么杠杆可以视为距该支点1.5单位的一个质量为W的物块,会影响平衡。

这里可以使用逆向思维,仅作思路简化。如何拿,不如如何放。如果能依次放上物块且保持平衡,那么逆序即为拿的解。

考虑如何放的问题,每一个物块有其力矩。优先选取较小的放对整个系统的平衡影响最小。所以,需要对物块进行按力矩排序。排序后,在右侧放上一个物块,判断是否平衡,如果平衡说明还能承受那么可以继续放,如果不能,则尝试在左侧放,左右交替直至放完所有方块得解或者杠杆已经不能承受(Impossible)。

[-30 -32 -40 64 35 8]-3 -8 (-4) 8 5 2-3 -8 (-4 8) 5 2-3 (-8 -4 8) 5 2-3 (-8 -4 8 5) 2(-3 -8 -4 8 5) 2(-3 -8 -4 8 5 2)

这里有一个问题,并不一定能够摆到最后一个物块,可能在之前便已经穷尽摆法。所以这里有两个递归基,一个是达到了最后一个物块,另一个是隐式无结果(return;),所以这里设立一个flag表示是否已达最后一个物块。

如何判断杠杆是否平衡?
考察左侧支点,将左侧物块的力矩计算和(其实这里存在-1.5~0区间的物块,但其负增益可以视为在右侧放置物块。),再将右侧的物块的力矩计算和(注意还有杠杆本身)。判断是否左翻(右翻还需要考察其压着的右侧支点)。再同理考察右侧支点。

与其他解法相比,这里的解法没有完全的进行左右支点的分割,部分整体部分局部的考虑实属意外之解,另外可以参考其他解法使用DP压缩等等 : P

代码

#include <cstdio>#include <algorithm>#define MAX_N 25using std::sort;int W, N, li, ri, flag;struct object { int p, w; } L[MAX_N], R[MAX_N], A[MAX_N];int cmp(object f, object s) { return (f.p * f.w) < (s.p * s.w); }bool is_balanced(int l, int r){    double wl = 0, wr = 0;    for (int i = 0; i < r; i++) wr += (R[i].p + 1.5) * R[i].w;    for (int i = 0; i < l; i++) wl += (L[i].p - 1.5) * L[i].w;    if ( wl > wr + 1.5 * W ) return false;    wl = 0, wr = 0;    for (int i = 0; i < r; i++) wr += (R[i].p - 1.5) * R[i].w;    for (int i = 0; i < l; i++) wl += (L[i].p + 1.5) * L[i].w;    if ( wl + 1.5 * W < wr ) return false;    return true;}void dfs(int l, int r, int n){    if (n == N) {        for (int i = N - 1; i >= 0; i--)            printf("%d %d\n", A[i].p, A[i].w);        flag = 1;        return;    }    for (int i = l; i < li; i++)        if (is_balanced(i, r) && !flag) {            A[n].p = -L[i].p; A[n].w = L[i].w;            dfs(i + 1, r, n + 1);        } else break;     for (int i = r; i < ri; i++)        if (is_balanced(l, i) && !flag) {            A[n].p =  R[i].p; A[n].w = R[i].w;            dfs(l, i + 1, n + 1);        } else break;}void solve(){    sort(R, R + ri, cmp); sort(L, L + li, cmp);    flag = 0; dfs(0, 0, 0);    if (!flag) printf("Impossible\n");}int main(){    int T = 0, p, w;    while (scanf("%*d%d%d", &W, &N), (W + N)) {        li = 0, ri = 0;        for (int i = 0; i < N; i++) {            scanf("%d%d", &p, &w);            if (p > 0) { R[ri].p =  p; R[ri].w = w; ri++; }            else       { L[li].p = -p; L[li].w = w; li++; }        }        printf("Case %d:\n", ++T);        solve();    }    return 0;}

题目

Description

As Archimedes famously observed, if you put an object on a lever arm, it will exert a twisting force around the lever’s fulcrum. This twisting is called torque and is equal to the object’s weight multiplied by its distance from the fulcrum (the angle of the lever also comes in, but that does not concern us here). If the object is to the left of the fulcrum, the direction of the torque is counterclockwise; if the object is to the right, the direction is clockwise. To compute the torque around a support, simply sum all the torques of the individual objects on the lever.

The challenge is to keep the lever balanced while adjusting the objects on it. Assume you have a straight, evenly weighted board, 20 meters long and weighing three kilograms. The middle of the board is the center of mass, and we will call that position 0. So the possible positions on the board range from -10 (the left end) to +10 (the right end). The board is supported at positions -1.5 and +1.5 by two equal fulcrums, both two meters tall and standing on a flat floor. On the board are six packages, at positions -8, -4, -3, 2, 5 and 8, having weights of 4, 10, 10, 4, 7 and 8 kilograms, respectively as in the picture below.

Your job is to remove the packages one at a time in such a way that the board rests on both supports without tipping. The board would tip if the net torque around the left fulcrum (resulting from the weights of the packages and the board itself) were counterclockwise or if the net torque around the right fulcrum were clockwise. A possible solution to this problem is: first remove the package at position -4, then the package at 8, then -8, then 5, then -3 and finally 2.

You are to write a program which solves problems like the one described above.

Input

The input contains multiple cases. Each case starts with three integers: the length of the board (in meters, at least 3), the weight of the board (in kilograms) and n the number of packages on the board (n ≤ 20). The board is supported at positions -1.5 and +1.5 by two equal fulcrums, both two meters tall and standing on a flat floor. The following n lines contain two integers each: the position of a package on board (in meters measured from the center, negative means to the left) and the weight of the package (in kilograms). A line containing three 0’s ends the input.

Output

For each case you are to output the number of the case in the format shown below and then n lines each containing 2 integers, the position of a package and its weight, in an order in which the packages can be removed without causing the board to tip. If there is no solution for a case, output a single line Impossible. There is no solution if in the initial configuration the board is not balanced.

Sample Input

20 3 6-8 4-4 10-3 102 45 78 820 3 151 108 5-6 85 9-8 48 10-3 10-4 52 9-2 23 3-3 25 1-6 12 530 10 2-8 1009 910 0 0

Sample Output

Case 1:-4 108 8-8 45 7-3 102 4Case 2:1 108 5-6 85 9-8 48 10-3 10-4 52 9-2 23 3-3 25 1-6 12 5Case 3:Impossible
0 0
原创粉丝点击