UVA10123木板上放石头使木板平衡,递归加强剪枝
2015-10-06 23:27
381 查看
渣渣表示物理没学好,读完题的第一感觉是题意读错了,又反复读了好几遍,才感觉没读错,
只不过物理没学好,感觉取一个石头是不可能平衡的,然而是可以的,因为有俩个支点,又不是一个,
然后怎样去保持平衡,以左边支点分析,右边支点忽略,如果左边的力矩大于右边的力矩加上1.5乘于木板的
总重量,这里为什么要加这个东西,不理解,后来想了很久,另外咨询了我们班学霸,这里相当于把木板的总重量
抽象为在木板中间,也就是传说的质心,然后力距就是1.5。然后是这个题的做法,这个题爆搜毫无疑问会T,关键在于怎么剪枝,
首先反向思维,放完石头去取相当于没放石头的时候一个一个放石头,然后放的时候,把左边和右边分开,分别按照力矩的大小进行排序,
这里,肯定你放石头的时候先放的是对木板平衡影响比较小的,然后左边不能平衡的时候,在放右边的石头,如此往复,如果左后全部的石头
能够放完,反向输出就是答案了。这里的剪枝很关键,也比较巧妙,不经过分析是
不可能想到这么剪枝的。
只不过物理没学好,感觉取一个石头是不可能平衡的,然而是可以的,因为有俩个支点,又不是一个,
然后怎样去保持平衡,以左边支点分析,右边支点忽略,如果左边的力矩大于右边的力矩加上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; }
不可能想到这么剪枝的。
相关文章推荐
- leetcode题目 跳跃游戏系列题目
- HDU3966【树链剖分】。
- 提高Android Studio中Gradle执行效率
- openstack手动安装
- 一些安卓开源框架整理
- 屏蔽浏览器窗口自带的事件
- linq to object 未完待续
- loadView、viewDidLoad及viewDidUnload的关系
- VB 连接AutoCad 模块代码
- 结对项目博客
- ubuntu装jdk
- Tomcat连接池的配置
- Java web 图片上传(文件上传)
- 从今天开始,每天写一篇博客
- 个人博客作业_week3
- jquery easyui DataGrid
- 排序算法的C语言实现
- [iOS开发项目-7] 超级猜图
- PHP 字符串编码的转换
- 约瑟夫环(N个人围桌,C语言,数据结构)