【题目大意】
| |
| |
| |___________
|________________
有像上面这样一个直角拐角(一个口宽为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;
}