Q2:
等周问题.
话说柴小俊成功修完水管之后,实力大增(节省了材料),成功攻占了地方阵营,经过谈判,在敌方阵营中(一个三角形区域),柴小俊能够用长度为L的绳子圈出一块区域作为自己的领地,那么机智的你,能否告诉柴小俊他最多能够圈多大的面积呢?
输入:
给出三角形三个顶点的坐标、 绳长L。
输出:
柴小俊能够圈出的最大面积。
分析:首先我们脱离这个具体问题本身,来想清楚另外一个问题:周长L的所有平面几何图形中,面积最大的是谁?
其实这就是著名的等周问题,答案是圆。其最严谨的证明在数学分析的课本中往往会介绍变分法来证明,但是这里我们利用一个初等的技巧来简单的证明一下。
证明:
首先我们能够看到,最大面积的图形必然是“凸型曲线”,因为如果是凹陷的,我们能够将凹陷处向外翻折,周长没变但是显然面积增大了。
其次,我们应该看到,最大面积图形中,任取一点A,再做另外一点B,使得曲线AB的长度是L的一半,直线AB左右两侧的面积应该是相同的。因为如果不同,我们可以做那个面积较大的部分关于AB的对称,依然是周长没变,面积变大。
最后,基于上边的要点,我们发现,只要找到了不闭合曲线L/2和直线AB围成图形的最大面积,那么我们通过对称就可以得到最终的最大面积图形。这里在长度为L/2的不闭合曲线上取一个点C,假设这里弦AC及其对应的弧围成的面积是最大的、BC及其对应的弧围成的面积是最大的,那么现在最优解的问题又转化了:一直三角形的两边AC、BC,△ABC的最大面积是多少?很显然,由三角形的面积公式S=1/2absinC可知,C是直角的时候面积最大。那么在这段弧上处处取这样的点,都要满足这个结论,最终我们会得到一个半圆。
最后我们就得到了一个圆。
证毕。
那么我们现在再次回到这个问题,会出现如下三种情况:
(1)L小于三角形内切圆的周长,那么这表明L可以在三角形内部圈出一个完整的圆。
(2)L大于三角形的周长,那么圈出的面积就是这个三角形。
(3)介于二者之间。
能够看到,对于(1)(2)两种情况非常好处理,难处理的是(3)。
看这样一个图。
首先我们要搞明白这种情况下的曲线的性质。
这里首先确定这样一件事情:图中直线部分的长度和曲线部分长度分别都是定值,然后对于曲线部分,利用等周定理,我们应该拼出一个圆才能够使得面积最大。
也就是我们得到这样要给结论,这种情况下最大面积的图形,三段曲线是一个整圆的三部分。
然后依据性质做具体而有效的计算。
S(白) = S(大三角)-S(小三角)+S(小内切圆)
结合初等数学相似比的方法,便可求解。
简单的参考代码如下:
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<string.h>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<functional>
#include<map>
using namespace std;
const int maxn = 200 + 10;
const int INF = (int)1e9;
const double eps = 1e-9;
const double pi = 3.1415927;
double a, b, c, l;//l是篱笆长度
bool cmp(double a, double b) {
return a < b;
}
int main()
{
double len, hl, cosc;
double area, res;//三角形面积 篱笆围得面积
double r, k;
int tt = 1;
double edge[3];//储存边长
while (scanf("%lf %lf %lf %lf", &edge[0], edge[1], &edge[2], &l) != EOF) {
if (fabs(edge[0]) < eps && fabs(edge[1]) < eps && fabs(edge[2]) < eps && fabs(l) < eps)
break;
sort(edge, edge + 3, cmp);
a = edge[0];
b = edge[1];
c = edge[2];
len = a + b + c;//周长
cosc = (a*a + b*b - c*c) / (2 * a*b);//余弦定理 求cosC
if (fabs(cosc) < eps) {//直角三角形
area = a*b / 2;
r = (a + b - c) / 2.0;
}
else {
area = a*b*sqrt(1 - cosc*cosc)*0.5;
r = area*2.0 / len;
}
//开始判断
if (2 * pi*r >= l) { //篱笆长度小于内切圆周长
r = l / (2 * pi);
res = pi*r*r;
}
else if (l >= len) //篱笆长度大于三角形面积
res = area;
else {//位于两者之间
k = (len - l) / (len - 2 * pi*r);
r = r*k;//小内切圆半径
res = area - area*k + pi*r*r; //大三角形面积-小三角形面积+小内切圆面积
}
printf("Case %d: %.2f", tt++, res);
}
//system("pause");
return 0;
}