【题目大意】
| |
| |
| |___________
|________________
有像上面这样一个直角拐角(一个口宽为a,一个口宽为b),两边走廊可以认为是无限长。
问一个表面光滑的长为l的矩形宽w(宽当然比长小了)最大是多少。
【输入】
一行三个整数,a、b、l
【输出】
一个实数w,要求误差不超过10^-7
1A……两道作业题我都是1A,不科学啊……明明很没信心的
我们来考虑一下这个矩形滑过去的过程,来分几种情况讨论一下
讨论的时候为了方便令a<=b
1、l<=a
这种情况w<=l<=a,怎么他都不会卡住啊!所以令w=l
2、a<=l<=b
这种情况如果a<=w<=l<=b
那么……
他掉不到拐角处,入口处就被卡着了……
令w=a
可以直接推到拐角处,然后再从另外一边推出来
这时候答案w=a
3、b<=l
这是最一般的情况。
设f(x)表示宽为x的矩形是否能够通过,显然这个函数具有单调性。
问题就转化到如何实现函数f(x)。
可以把转弯的过程看作l这条边贴着墙壁先降到最底层,然后靠着墙慢慢转过来。
这个时候距离那个很尖锐的点的距离(如果穿过墙了我们认为距离是负的)关于l那条边跟外侧某条边的墙的夹角x是个单峰函数。
三分即可求出峰值。具体怎么做就不赘述了。
#include <cstdio> #include <iostream> #include <cmath> using namespace std; int a,b,l; double s,e,mid; double quick(double x,double w) { double o,p,q; if (x<1e-8) o=1,p=0,q=0; else if (x>asin(1)-1e-8) o=0,p=1,q=0; else o=-tan(x),p=-1,q=l*sin(x)+w/cos(x); return -(o*a+p*b+q)/sqrt(o*o+p*p); } double calc(double w) { double x,y,s,e; s=0; e=asin(1); while (e-s>1e-8) { x=s+(e-s)/3; y=e-(e-s)/3; if (quick(x,w)<quick(y,w)) e=y; else s=x; } return quick(s,w); } int main() { cin >> a >> b >> l; if (a>b) swap(a,b); if (l<=a) printf("%.7f",(double)l); else if (l<=b) printf("%.7f",(double)a); else { s=0; e=a; while ((e-s)>1e-8) { mid=(s+e)/2; if (calc(mid)<1e-8) e=mid; else s=mid; } if (calc(s)<1e-8) printf("My poor head =("); else printf("%.7f",s); } cout << endl; cin.get(); cin.get(); return 0; }