题目地址:
题目描述:
Problem A - No Tipping
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.
You are to write a program which solves problems like the one described above. 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. 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 10 2 4 5 7 8 8 20 3 15 1 10 8 5 -6 8 5 9 -8 4 8 10 -3 10 -4 5 2 9 -2 2 3 3 -3 2 5 1 -6 1 2 5 30 10 2 -8 100 9 91 0 0 0Possible Output for sample input
Case 1: -4 10 8 8 -8 4 5 7 -3 10 2 4 Case 2: 1 10 8 5 -6 8 5 9 -8 4 8 10 -3 10 -4 5 2 9 -2 2 3 3 -3 2 5 1 -6 1 2 5 Case 3: Impossible
题意:杠杆 放砝码,然后一个一个取走,保证过程中,杠杆不侧翻。
题解:两种方法。
一、DFS剪枝+物理力矩+贪心二、状态压缩+记忆话搜索 ...
一:将放上去的砝码做一个逆变换,即初始化为杠杆上没有砝码,我们一个一个往上放,使其过程中不发生侧翻的情况。
侧翻的情况:当左边点的左端的力矩大于左边点的右端的力矩,会往左侧翻;当右边点的右端的力矩大于右边点的左端的力矩,会往右侧翻。
注意点:
1、处理时将坐标放大两倍,使1.5->3省略小数的处理。
2、处于-1.5~+1.5之间的先放,可以证明其不会影响杠杆的侧翻(剪枝)。
3、在此区间以外的分为两组,-L~-1.5为左组 +1.5~+L为右组,将两组按对应点力矩升序排列,放砝码时,若放最大的,很可能会引起侧翻,所以尽可能维持平衡,从影响度最小的开始放,再放大的,这样到后面这些若干小的可以缓和另一侧大的砝码的侧翻影响效应,从而尽可能维持平衡(若实在无法维持平衡 那就是impossible)。所以整个DFS过程可以贪心地去一边的砝码,比如左边的按升序先放砝码,一直到左边再放一个就会引起侧翻后,再到右边的按升序放,用来抑制左边会侧翻的情况,若左边还是侧翻继续往右边放,直到左边可以放为止,注意左右两组砝码都是有序的,这样省去了无序砝码的遍历查找时间(剪枝)。一直维持这个过程,直到所有砝码都放上去,也没有出现侧翻的条件就ok;如果出现这样的情况,无论放左边还是放右边的都有侧翻情况发生,那么这一种情况就是impossible的。(感觉这样的模式与快排的算法模式有点相似)
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct Packages
{
/* data */
int Len;//length
int We;//weight
int ll;//torque left point on left side
int lr;//torque left point on right side
int rr;
int rl;
Packages()
{
Len=0;
We=0;
ll=0;
lr=0;
rr=0;
rl=0;
}
}P,*PLink;
P MidP[20+5];//the package int the between -3 and +3,the 1.5*2=3,we have magified the number
int cntM=0;// the count of the array;
P LeftP[20+5];//-L~-3
int cntL=0;
P RightP[20+5];//+3~+L
int cntR=0;
P OutP[20+5];//the place on the order, we should print ot in the comtrary order
int cntO=0;
int Cases=0;
int n=0;//the number of the packages
int L=0;//the length of the board
int W=0;//the weight of the board
double LL=0,LR=0,RR=0,RL=0;//the torque of the sum
int flag=0;
/*cmp for the sort*/
bool cmpL(P a,P b)
{
return(a.ll<b.ll);//we concern about that the LL>LR or the RR > RL so the LL and RR 's plus is so sensitive, so we sort by the ll and rr of the torque
}
/*cmp for the sort*/
bool cmpR(P a,P b)
{
return(a.rr<b.rr);
}
/*for test*/
int test()
{
return(0);
}
/*DFS the place scheme*/
int DFS(int curS,int curL,int curR)//cur is the index of the array it is have been not placed it all
{
if(flag)
{
return(0);
}
if(LL>LR || RR>RL)//the balanced lever arm will be destroied
{
return(0);
}
if(curS==n)//all packages can safely place on the lever arm
{
flag=1;
return(0);
}
if(curL<=cntL-1)
{
LL+=LeftP[curL].ll;
RL+=LeftP[curL].rl;
memcpy(OutP+cntO,LeftP+curL,sizeof(LeftP[curL]));
cntO++;
DFS(curS+1,curL+1,curR);
if(flag)
{
return(0);//prevent the outP array recover
}
cntO--;
RL-=LeftP[curL].rl;
LL-=LeftP[curL].ll;
}
if(curR<=cntR-1)
{
RR+=RightP[curR].rr;
LR+=RightP[curR].lr;
memcpy(OutP+cntO,RightP+curR,sizeof(RightP[curR]));
cntO++;
DFS(curS+1,curL,curR+1);
if(flag)
{
return(0);//prevent the outP array recover
}
cntO--;
LR-=RightP[curR].lr;
RR-=RightP[curR].rr;
}
return(0);
}
/*main process*/
int MainProc()
{
while(scanf("%d%d%d",&L,&W,&n)!=EOF&&(L+W+n)>0)
{
//init
LL=RR=(L-3)*(L-3)*W/(4.0*L);// the lenth is 1.5 not 3: (l-3)/2 * (w * (l-3)/2/L ). the (l-3)/2 is the LL's length, the w*(l-3)/2/L is the LL's weight
LR=RL=(L+3)*(L+3)*W/(4.0*L);//the (L+3)/2 is the LR 's length = L/2 + 1.5
cntM=0;
cntL=0;
cntR=0;
cntO=0;
flag=0;
Cases++;
int i=0;
int length=0;
int weight=0;
for(i=0;i<=n-1;i++)
{
scanf("%d%d",&length,&weight);
length*=2;//1.5*2=3
if(abs(length)<=3)//add to the MidP
{
MidP[cntM].Len=length;
MidP[cntM].We=weight;
MidP[cntM].ll=0;//the package is not at this area
MidP[cntM].rr=0;
MidP[cntM].lr=abs((length-(-3))*weight);
MidP[cntM].rl=abs((length-3)*weight);
cntM++;
//update the torque
LR+=MidP[cntM-1].lr;
RL+=MidP[cntM-1].rl;
//update the out
memcpy(OutP+cntO,MidP+(cntM-1),sizeof(MidP[cntM-1]));
cntO++;
}
else if(length<-3)//add to the LeftP
{
LeftP[cntL].Len=length;
LeftP[cntL].We=weight;
LeftP[cntL].ll=abs((length-(-3))*weight);
LeftP[cntL].rl=abs((length-3)*weight);
LeftP[cntL].rr=0;
LeftP[cntL].lr=0;
cntL++;
}
else//add to the RightP
{
RightP[cntR].Len=length;
RightP[cntR].We=weight;
RightP[cntR].rr=abs((length-3)*weight);
RightP[cntR].lr=abs((length-(-3))*weight);
RightP[cntR].ll=0;
RightP[cntR].rl=0;
cntR++;
}
}
//sort the LeftP and the /RightP
sort(LeftP,LeftP+cntL,cmpL);
sort(RightP,RightP+cntR,cmpR);
//according to the sort array dfs the place scheme
DFS(cntM,0,0);//sum place,left place ,right place
//output
printf("Case %d:\n",Cases );
if(flag)
{
for(i=cntO-1;i>=0;i--)
{
printf("%d %d\n",OutP[i].Len/2,OutP[i].We );
}
}
else
{
printf("Impossible\n");
}
}
return(0);
}
int main(int argc, char const *argv[])
{
/* code */
MainProc();
return 0;
}