zoj 2614 Bridge 积分 (公式 和 simpson ) + 二分

问题最终转化成 过原点和 (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;  
} 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值