UVA - 12475 :求椭圆的周长,精度要求很高

暑期电大组队训练赛的一题。 题意是给出椭圆的长半轴a和b,求椭圆的周长,精度要求很高!  

关于椭圆周长(L)的精确计算要用到积分或无穷级数的求和.
UVA - 12475 :求椭圆的周长,精度要求很高_第1张图片
//显然直接利用积分计算太困难,而利用被转化过来的级数计算则显然方便的多。只是循环到多大级数才算最好。我参照一篇论文(但依据论文写的程序很多小数据并不能过)提供的数据
 
 
  
  
  
  

   

  公式(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

将级数定在10^5的时候,精度已经满足要求了。
#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
*/


 
 
 
 

你可能感兴趣的:(UVA - 12475 :求椭圆的周长,精度要求很高)