uva 10012How Big Is It?
来源:互联网 发布:安卓魔音软件 编辑:程序博客网 时间:2024/06/10 12:02
原题:
Ian’s going to California, and he has to pack his things, including his collection of circles. Given a set of circles, your program must find the smallest rectangular box in which they fit. All circles must touch the bottom of the box. The figure below shows an acceptable packing for a set of circles (although this may not be the optimal packing for these particular circles). Note that in an ideal packing, each circle should touch at least one other circle (but you probably figured that out).
Input
The first line of input contains a single positive decimal integer n, n ≤ 50. This indicates the number of lines which follow. The subsequent n lines each contain a series of numbers separated by spaces. The first number on each of these lines is a positive integer m, m ≤ 8, which indicates how many other numbers appear on that line. The next m numbers on the line are the radii of the circles which must be packed in a single box. These numbers need not be integers.
Output
For each data line of input, excluding the first line of input containing n, your program must output the size of the smallest rectangle which can pack the circles. Each case should be output on a separate line by itself, with three places after the decimal point. Do not output leading zeroes unless the number is less than 1, e.g. 0.543.
Sample Input
3
3 2.0 1.0 2.0
4 2.0 2.0 2.0 2.0
3 2.0 1.0 4.0
Sample Output
9.657
16.000
12.657
中文:
有个人要去旅行要带一堆圆环,现在给出你这些圆环的半径,问你如何摆放,使得需要的箱子长度最小?
#include<bits/stdc++.h>using namespace std;typedef long long ll;const double inf=99999999;double circle[9],ans,tmp,X[9];int n;double my_abs(double x){ if(x<0) return -x; return x;}double get_dis(int c1,int c2){ double a=circle[c1]+circle[c2]; double b=my_abs(circle[c1]-circle[c2]); return sqrt(a*a-b*b);}//与第i个圆相切的圆一定是x坐标最远的那个void solve(){ do { memset(X,-1,sizeof(X)); X[1]=circle[1]; tmp=-1; for(int i=2;i<=n;i++) { double x_=circle[i]; for(int j=1;j<i;j++)//找最大的 x_=max(x_,X[j]+get_dis(i,j)); X[i]=x_; }// cout<<endl;// for(int i=1;i<=n;i++)// cout<<X[i]<<" ";// cout<<endl;// for(int i=1;i<=n;i++)// cout<<circle[i]<<" ";// cout<<endl; for(int i=1;i<=n;i++) tmp=max(tmp,X[i]+circle[i]);// cout<<fixed<<setprecision(3)<<tmp<<endl; ans=min(ans,tmp); } while(next_permutation(circle+1,circle+1+n));}int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--) { cin>>n; for(int i=1;i<=n;i++) cin>>circle[i]; ans=inf; sort(circle+1,circle+1+n); solve(); cout<<fixed<<setprecision(3)<<ans<<endl; } return 0;}//3 8 1 2//
解:
刚一看这题觉得挺简单的,直接搜索或者用生成排列呗。结果在纸上一算,发现有好多坑。
首先,最简单的情况,如果圆的半径相差不大,那么直接顺序排列就行了。
第二种,有半径相差比较大的圆,那么小的那个圆可以塞到大圆与箱底的那个“缝隙”当中。
第三种,如果有半径相差比较大的圆,小圆那个圆”靠墙”,那么大的那个圆也要”靠墙”。
考虑这三种情况之后,可以很容易的想到暴力+贪心的策略来解决,也就是每次枚举圆的排列顺序,然后把圆尽量贴到它最左侧的圆环。但是由于数据给出的是半径,而不是坐标,所以要把之前排列好的圆用坐标的方式表达出来。
每个圆的纵坐标都固定是它的半径,横坐标要算出用到它前面那个圆的横坐标,然后再加上当前圆和它前面那个圆的圆心的水平距离。
在代码中get_dis(c1,c2)表示计算第c1个圆和第c2个圆之间的水平距离。X[]数组记录圆的横坐标。考虑第i圆如何选择,与之前所有摆放好的圆环进行相切,然后记录下所有的横坐标距离,找出最大的那个横坐标,就是第i个圆应该摆放的位置。如图
黑色的圆是之前摆放好的,第i个圆分别与前面的3个黑圆相切处理,找到最靠右,也就是横坐标最大的那个就是应该摆放的位置(如图的红圈就是)
此题也可以剪枝处理,当然,此时要用深搜,如果摆放的一些的圆环还没有摆放完就发现比之前找到的解还要大,就可以剪枝了。
- uva 10012 how big is it?
- uva 10012 How Big Is It?
- uva 10012 - How Big Is It?
- UVa 10012 - How Big Is It?
- [uva] 10012 - How Big Is It?
- UVa 10012 - How Big Is It?
- UVa 10012 - How Big Is It?
- uva 10012 How Big Is It?
- uva 10012 - How Big Is It?
- UVA 10012 How Big Is It?
- uva 10012How Big Is It?
- UVA - 10012 How Big Is It?
- UVA 10012 How Big Is It?
- uva 10012How Big Is It?
- UVA How Big Is It?
- UVa 10012 - How Big Is It? 圆排列问题
- UVa 10012 How Big is It? (计算几何+DFS)
- UVA 10012 How Big Is It?(暴力枚举)
- javaWeb基础知识----JSTL
- ViewPager实现图片轮播
- 仿IOS弹出相机相册框--可进入相机相册仿朋友圈功能的demo
- drawRect方法绘图
- web项目部署到tomcat服务器
- uva 10012How Big Is It?
- 回归提升树 算法
- MySQL数据备份与还原
- Java多线程生产者和消费者的例子
- SQL索引详解
- 141. Linked List Cycle (Easy)
- 数列(矩阵乘法+快速幂)
- Java设计模式15——命令模式
- 我的嵌入式学习第一天