UVA10123木板上放石头使木板平衡,递归加强剪枝

来源:互联网 发布:怎么复制淘宝宝贝标题 编辑:程序博客网 时间:2024/04/27 14:20

渣渣表示物理没学好,读完题的第一感觉是题意读错了,又反复读了好几遍,才感觉没读错,

只不过物理没学好,感觉取一个石头是不可能平衡的,然而是可以的,因为有俩个支点,又不是一个,

然后怎样去保持平衡,以左边支点分析,右边支点忽略,如果左边的力矩大于右边的力矩加上1.5乘于木板的

总重量,这里为什么要加这个东西,不理解,后来想了很久,另外咨询了我们班学霸,这里相当于把木板的总重量

抽象为在木板中间,也就是传说的质心,然后力距就是1.5。然后是这个题的做法,这个题爆搜毫无疑问会T,关键在于怎么剪枝,

首先反向思维,放完石头去取相当于没放石头的时候一个一个放石头,然后放的时候,把左边和右边分开,分别按照力矩的大小进行排序,

这里,肯定你放石头的时候先放的是对木板平衡影响比较小的,然后左边不能平衡的时候,在放右边的石头,如此往复,如果左后全部的石头

能够放完,反向输出就是答案了。这里的剪枝很关键,也比较巧妙,不经过分析是

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <map>#include <set>#include<cmath>#include<climits>#include<vector>#include<cfloat>#include<queue>#include<cctype>#include<cstdlib>#define LL long longusing namespace std;const int maxn=30;int L,W,N,li,ri,flag;struct node{    int p,w;}l[maxn],r[maxn],a[maxn];int cmp(node a,node b){    return (a.p*a.w)<(b.p*b.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 0;    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 0;    return 1;}void dfs(int L,int R,int n){    if(n==N)    {        for(int i=n-1;i>=0;i--)            cout<<a[i].p<<' '<<a[i].w<<endl;        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 slove(){    sort(l,l+li,cmp);    sort(r,r+ri,cmp);    flag=0;    dfs(0,0,0);    if(!flag) cout<<"Impossible"<<endl;}int main(){    int t=0;   while(scanf("%d%d%d",&L,&W,&N)&&L+W+N)   {       li=0,ri=0;       for(int i=0;i<N;i++)       {           int p,w;           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++;}       }       cout<<"Case "<<++t<<':'<<endl;       slove();   }    return 0;}

不可能想到这么剪枝的。


0 0
原创粉丝点击