您的位置:首页 > 其它

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

2013-10-01 15:50 435 查看
问题最终转化成 过原点和 (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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: