您的位置:首页 > 其它

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

2015-10-06 23:27 381 查看
渣渣表示物理没学好,读完题的第一感觉是题意读错了,又反复读了好几遍,才感觉没读错,

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

然后怎样去保持平衡,以左边支点分析,右边支点忽略,如果左边的力矩大于右边的力矩加上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 long
using 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
.p=-l[i].p;
a
.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
.p=r[i].p;
a
.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;
}


不可能想到这么剪枝的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: