1.题目描述:点击打开链接
2.解题思路:本题算是一道微积分题目,首先根据题目条件列写方程:间隔数n=ceil(B/D),每个间隔宽度D1=B/n,每段绳索长度L1=L/n。接下来就是根据D1,L1来计算底部离地面的高度y了。不过我们会发现,这个方程很难找到求解公式,因此应该转移思路,试图利用数值问题中的二分法逐渐逼近这个高度值。设函数P(w,h)计算出来抛物线的长度,其中w表示抛物线开口的宽度,h表示抛物线的高度,那么不难发现,这个函数是一个单调函数:当w固定时,它随着h的增大而增大。由于抛物线长度也是确定的,因此此时可以通过二分法求解高度h。
那么,该如何计算P(w,h)这个函数呢,我们可以利用微积分中的弧长公式来计算弧长,同时可以查表求出这个弧长公式的原函数,从而求得弧长,具体过程略去。
由于本题涉及积分的运算,因此随后附上利用数值积分的解法——自适应辛普森算法。
3.代码:
(一,利用微积分公式求解)
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<functional> using namespace std; typedef long long LL; double F(double a, double x)//求sqrt(a^2+x^2)的原函数 { double a2 = a*a, x2 = x*x; return (x*sqrt(a2 + x2) + a2*log(fabs(x + sqrt(a2 + x2))))/2; } double P(double w, double h)//求弧长 { double a = 4.0*h / w / w; double b = 1.0 / 2 / a; return (F(b, w / 2) - F(b, 0)) * 4 * a; } int main() { //freopen("t.txt", "r", stdin); int T; cin >> T; for (int rnd = 1; rnd <= T; rnd++) { int d, h, b, l; cin >> d >> h >> b >> l; int n = (b + d - 1) / d; double d1 = (double)b / n; double l1 = (double)l / n; double x = 0, y = h; while (y - x > 1e-5)//利用二分法求解高度h { double m = x + (y - x) / 2; if (P(d1, m) < l1)x = m; else y = m; } if (rnd>1)cout << endl; printf("Case %d:\n%.2lf\n", rnd, h - x); } return 0; }
(二,利用自适应辛普森算法求解)(注:关于自适应辛普森算法的讲解,随后会在“算法归纳与小结”中介绍)
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<functional> using namespace std; typedef long long LL; double a;//为了便于处理,设为全局变量 double F(double x)//Simpson公式用到的函数 { return sqrt(1 + 4 * a*a*x*x); } double simpson(double a, double b)//三点Simpson法,这里要求F是一个全局函数 { double c = a + (b - a) / 2; return (F(a) + 4 * F(c) + F(b))*(b - a) / 6; } double asr(double a, double b, double eps, double A)//自适应Simpson公式(递归过程)。已知整个区间[a,b]上的三点Simpson值A { double c = a + (b - a) / 2; double L = simpson(a, c), R = simpson(c, b); if (fabs(L + R - A) <= 15 * eps)return L + R + (L + R - A) / 15.0; return asr(a, c, eps / 2, L) + asr(c, b, eps / 2, R); } double asr(double a, double b, double eps)//自适应Simpson公式(主过程) { return asr(a, b, eps, simpson(a, b)); } double P(double w, double h)//用自适应Simpson公式计算宽度为w,高度为h的抛物线长 { a = 4.0*h / w / w;//修改全局变量,从而修改全局函数F的行为 return asr(0, w / 2, 1e-5) * 2; } int main() { //freopen("t.txt", "r", stdin); int T; cin >> T; for (int rnd = 1; rnd <= T; rnd++) { int D, H, B, L; scanf("%d%d%d%d", &D, &H, &B, &L); int n = (B + D - 1) / D; double D1 = (double)B / n; double L1 = (double)L / n; double x = 0, y = H; while (y - x > 1e-5) { double m = x + (y - x) / 2; if (P(D1, m) < L1)x = m; else y = m; } if (rnd>1)cout << endl; printf("Case %d:\n%.2lf\n", rnd, H - x); } return 0; }