问题最终转化成 过原点和 (x,y) 的抛物线 y = k*x^2 ,知道 (0,0)到(x,y)的曲线长度 s和 x 的值,求y 的值。
二分 y, 求 长度(用到积分)。直到接近 s 为止。
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <stack> #include <cstring> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <ctime> #include <assert.h> #include <queue> #define REP(i,n) for(int i=0;i<n;i++) #define TR(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++) #define ALLL(x) x.begin(),x.end() #define SORT(x) sort(ALLL(x)) #define CLEAR(x) memset(x,0,sizeof(x)) #define FILLL(x,c) memset(x,c,sizeof(x)) using namespace std; const double eps = 1e-9; #define LL long long #define pb push_back const int maxn = 1100; double d ,h, b,l; double f(double a,double x){ return x/2*sqrt(a*a+x*x) + a*a/2 *log(fabs(x+ sqrt(a*a+x*x))); } double get_ans( double y,double x){ double k = y/(x*x); double ret = 0; ret += 2*k *( f(1/(2*k),x) -(f(1/(2*k), 0))); return ret; } void solve(){ int kk = ceil(b/d); double len = b/kk; double s= l/(2*kk); double x = len/2; double left = 0; double right = h; int t = 100; while(t--){ double mid = (left +right)/2; double tmp = get_ans(mid,x); if(tmp<s){ left = mid; }else{ right = mid; } } // cout << left << " "<< right <<endl; printf("%.2f\n",h-left); } int main(){ int t ; cin >> t ; int cas =0; while(~scanf("%lf%lf%lf%lf",&d,&h,&b,&l),t--){ cas ++ ; if(cas>1)printf("\n"); printf("Case %d:\n",cas); solve(); } return 0; }
此问题转化为 求 sqrt( 4*k ^2 *x^2 +1) 的积分 。
利用simpson 算法。
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <stack> #include <cstring> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <ctime> #include <assert.h> #include <queue> #define REP(i,n) for(int i=0;i<n;i++) #define TR(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++) #define ALLL(x) x.begin(),x.end() #define SORT(x) sort(ALLL(x)) #define CLEAR(x) memset(x,0,sizeof(x)) #define FILLL(x,c) memset(x,c,sizeof(x)) using namespace std; const double eps = 1e-9; #define LL long long #define pb push_back const int maxn = 1100; double d ,h, b,l; double k; double F(double x) { return sqrt(4*k*k*x*x+1); } // 三点simpson法。这里要求F是一个全局函数 double simpson(double a, double b) { double c = a + (b-a)/2; return (F(a)+4*F(c)+F(b))*(b-a)/6; } // 自适应Simpson公式(递归过程)。已知整个区间[a,b]上的三点simpson值A double asr(double a, double b, double eps, double 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); } // 自适应Simpson公式(主过程) double asr(double a, double b, double eps) { return asr(a, b, eps, simpson(a, b)); } double get_ans(double y1,double x1){ k= y1 / (x1*x1); double ret = 0; ret += asr(0,x1,1e-4); //cout << y1 << " "<<x1 << " "<<ret << endl; return ret; } void solve(){ int kk = ceil(b/d); double len = b/kk; double s= l/(2*kk); double x = len/2; double left = 0; double right = h; int t = 100; while(t--){ double mid = (left +right)/2; double tmp = get_ans(mid,x); if(tmp<s){ left = mid; }else{ right = mid; } } printf("%.2f\n",h-left); } int main(){ int t ; cin >> t ; int cas =0; while(~scanf("%lf%lf%lf%lf",&d,&h,&b,&l),t--){ cas ++ ; if(cas>1)printf("\n"); printf("Case %d:\n",cas); solve(); } return 0; }