暑期电大组队训练赛的一题。 题意是给出椭圆的长半轴a和b,求椭圆的周长,精度要求很高!
关于椭圆周长(L)的精确计算要用到积分或无穷级数的求和.
//显然直接利用积分计算太困难,而利用被转化过来的级数计算则显然方便的多。只是循环到多大级数才算最好。我参照一篇论文(但依据论文写的程序很多小数据并不能过)提供的数据
|
公式(8)C值 |
椭圆周长真值 |
误差率 |
|
100 |
000 |
400.00000000 |
400.00000000 |
0.0000000000 |
100 |
001 |
400.10983309 |
400.10983297 |
0.0000000003 |
100 |
010 |
406.39741858 |
406.39741801 |
0.000000001 |
100 |
025 |
428.92108788 |
428.92108875 |
0.000000002 |
100 |
050 |
484.42241034 |
484.42241100 |
0.000000001 |
100 |
075 |
552.58730383 |
552.58730400 |
0.0000000003 |
100 |
090 |
597.31604626 |
597.31604325 |
0.000000005 |
100 |
099 |
625.18088484 |
625.18088479 |
0.0000000001 |
100 |
100 |
628.31853070 |
628.31853070 |
0.0000000000 |
#include<iostream>#include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> using namespace std; const double pi=acos(-1.0); int main() { int T,i,j; scanf("%d",&T); for(j=1;j<=T;j++) { double a,b,L; scanf("%lf%lf",&b,&a); L=2.0*pi*a; double e=1.0-b*b/a/a,sum=1.0,tmp=1.0,r; //这里的e保存的其实是表达式中e的平方 for(i=1;i<=100000;i++) { r=(2.0*i-1.0)/(2.0*i); tmp*=r*r*e; sum-=tmp/(2.0*i-1.0); } printf("Case %d: %.8lf\n",j,L*sum); } return 0; }
也有电大牛队不知道到用什么方法0ms快速AC。先复制代码如下参考!
#include<map> #include<set> #include<queue> #include<cmath> #include<cstdio> #include<vector> #include<string> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; #define lowbit(x) (x&(-x)) #define Max(a,b) a>b?a:b #define Min(a,b) a<b?a:b #define INF 0x7fffffff #define LLINF 922337203685477600LL #define LL __int64 #define MAXN 60000 #define MAXE 1100000 #define CH 129 #define eps 1e-8 #define PI acos(-1.0) #define mod 10000 #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 double a,b; const int MAXREAPET=1000; //计算次数 const double Eps=1e-9; struct Romberg { inline double f(double x) { return sqrt(a*a*sin(x)*sin(x)+b*b*cos(x)*cos(x)); } double T[2]; double S[2]; double R[2]; double C[2]; int loc[5]; double _Romberg(double a, double b) { // make sure that a < b double h, s, r, c, pre; int n = 1; int time = 4000; bool S2 = false, C2 = false, R2 = false; loc[2] = loc[3] = loc[4] = 1; T[loc[1] = 0] = (h = b - a) * (f(a) + f(b)) / 2; while (time--) { double sum = 0; for (int i = 0; i < n; i++) { sum += f(a + (i + 0.5) * h); } pre = T[loc[1]]; T[loc[1] ^= 1] = sum = (pre + sum * h) / 2.0; S[loc[2] ^= 1] = s = (4.0 * sum - pre) / 3.0; n += n; h = (b - a) / n; if (!(S2 = S2 || loc[2])) continue; C[loc[3] ^= 1] = c = (16.0 * s - S[loc[2] ^ 1]) / 15.0; if (!(C2 = C2 || loc[3])) continue; R[loc[4] ^= 1] = r = (64.0 * C[loc[3] ^ 1] - c) / 63.0; if (!(R2 = R2 || loc[4])) continue; if (fabs(r - R[loc[4] ^ 1]) < Eps) break; } return R[loc[4]]; } } G; double Getans(double x){ double y=(a*a*b*b-b*b*x*x)/(a*a); y=sqrt(y); double deg=atan(y/x); return G._Romberg(0,deg)*4+x*4; } int main() { //freopen("1.txt","r",stdin); //freopen("2.txt","w",stdout); int i,j,h; int T,n,m; int cas=1; while(~scanf("%lf%lf",&b,&a)) { double ans=0;; double left,right,leftmid,rightmid,leftans,rightans; left=0;right=a; printf("%.6f\n",Getans(0)); } return 0; } /* 2 5 10 3 4 */