NEERC 2014 D题 Damage Assessment

  • 题目描述
  • 直接计算定积分
  • 辛普森方法
  • Romberg方法

题目描述

这里是NEERC2014的相关资料,包括榜、题目、标程,但是好像没有解题报告。
这是CF上的重现Gym100553。
当然在ICPC Live Archive上也有,这里是链接,但是好像不能提交了。所以去CF上比较好。
牛客网上也有这道题,有的代码两边都能过,但有的代码只能过其中一边。数据应该是一样的,也许是SPJ与时限写的不同。
如图,一个油罐,两端是球缺,中间是一个圆柱体。倾斜以后,再给定一个液面高度,求液面的体积。

按如下示意建立一个坐标系,然后求一个定积分即可(定积分的计算可以看这里)
∫−h球缺l+h球缺f(x)dx\int_{-h_{球缺}}^{l+h_{球缺}}f(x)dx∫−h球缺​l+h球缺​​f(x)dx
其中,积分区域跟球缺的高度以及lll有关,而f(x)f(x)f(x)则是xxx处液体的横截面积,该面积要么为000,要么必然为一个弓形(当然整圆也可)。

直接计算定积分

这是CF上可以AC的代码,但是在牛客网T了两个点。

#include <bits/stdc++.h>
using namespace std;double const EPS = 3E-3;
double const PI = acos(-1.0);
double const INF = 1E100;inline int sgn(double x){return x>EPS?1:(x<-EPS?-1:0);}
inline bool is0(double x){return 0==sgn(x);}
inline bool isEq(double x,double y){return is0(x-y);}
inline double myasin(double x){if(x<-1.0)x=-1.0;else if(x>1.0)x=1.0;return asin(x);
}
inline double myacos(double x){if(x<-1.0)x=-1.0;else if(x>1.0)x=1.0;return acos(x);
}//计算定积分
double integral(double(*f)(double),double x1,double x2){double sum = 0.0;for(double x=x1;x<=x2;x+=EPS){sum += f(x);}return sum * EPS;
}//计算弓形的高度,半径为r,高度为h
inline double area(double r, double h){if(is0(r)||sgn(h)<=0) return 0.0;if(sgn(h-r-r)>=0) return PI * r * r;double a = r - h;double theta = myacos(a/r);return (theta - 0.5 * sin(theta+theta)) * r * r;
}double D;//球冠底面的直径
double L;//圆柱体的长度
double R,R2;//球冠的球的半径
double T;//倾斜以后,圆柱体母线的高度,即倾斜角就是arcsin(T/L)
double H;//剩下的油,其液面高度,是从圆柱体的底端开始计算
double Theta;
double hOfQiuque,xLeft,xRight,rOfYuanzhu;
double K,B;//y=kx+B;当k是INF表示x=B//计算x处的横截面积,这是一个弓形
double f(double x){double r = rOfYuanzhu;if(x<0){r = sqrt(R2-(x-xLeft)*(x-xLeft));}else if(x>L){r = sqrt(R2-(x-xRight)*(x-xRight));}double y0 = K*x + B;if(isEq(K,INF)) y0 = (x<=B?INF:-INF);return area(r,y0+r-rOfYuanzhu);
}double proc(){if(isEq(T,L)) K = INF, B = H;else Theta = asin(T/L), K = -tan(Theta), B = H / cos(Theta);rOfYuanzhu = 0.5 * D;xLeft = sqrt(R2-rOfYuanzhu*rOfYuanzhu);hOfQiuque = R - xLeft;xRight = L + hOfQiuque - R;return integral(f,-hOfQiuque,L+hOfQiuque);
}int main(){freopen("damage.in","r",stdin);freopen("damage.out","w",stdout);//freopen("1.txt","r",stdin);while(5==scanf("%lf%lf%lf%lf%lf",&D,&L,&R,&T,&H)){R2 = R * R;printf("%.6f\n",proc()/1E6);}return 0;
}

这个是牛客网上可以AC的,但是在CF上WA。

#include <bits/stdc++.h>
using namespace std;double const EPS = 1E-4;
double const PI = acos(-1.0);
double const INF = 1E100;inline int sgn(double x){return x>EPS?1:(x<-EPS?-1:0);}
inline bool is0(double x){return 0==sgn(x);}
inline bool isEq(double x,double y){return is0(x-y);}
inline double myasin(double x){if(x<-1.0)x=-1.0;else if(x>1.0)x=1.0;return asin(x);
}
inline double myacos(double x){if(x<-1.0)x=-1.0;else if(x>1.0)x=1.0;return acos(x);
}//计算定积分
double integral(double(*f)(double),double x1,double x2){double sum = 0.0;double fx;for(double x=x1;x<=x2;x+=EPS){sum += (fx = f(x));if(x>=0&&is0(fx)) break;}return sum * EPS;
}//计算弓形的高度,半径为r,高度为h
inline double area(double r, double h){if(is0(r)||sgn(h)<=0) return 0.0;if(sgn(h-r-r)>=0) return PI * r * r;double a = r - h;double theta = myacos(a/r);return (theta - 0.5 * sin(theta+theta)) * r * r;
}double D;//球冠底面的直径
double L;//圆柱体的长度
double R,R2;//球冠的球的半径
double T;//倾斜以后,圆柱体母线的高度,即倾斜角就是arcsin(T/L)
double H;//剩下的油,其液面高度,是从圆柱体的底端开始计算
double Theta;
//double A,B,C;//表示直线Ax+By=C;
double hOfQiuque,xLeft,xRight,rOfYuanzhu;
double K,B;//y=kx+B;当k是INF表示x=B//计算x处的横截面积,这是一个弓形
double f(double x){double r = rOfYuanzhu;if(x<0){r = sqrt(R2-(x-xLeft)*(x-xLeft));}else if(x>L){r = sqrt(R2-(x-xRight)*(x-xRight));}double y0 = K*x + B;if(isEq(K,INF)) y0 = (x<=B?INF:-INF);return area(r,y0+r-rOfYuanzhu);
}double proc(){/*if(is0(T)) A=0.0,B=1.0,C=H;else if(isEq(T,L))A=1.0, B=0.0, C=H;else Theta = myasin(T/L),A=sin(Theta),B=cos(Theta),C=H;//*/if(isEq(T,L)) K = INF, B = H;else Theta = asin(T/L), K = -tan(Theta), B = H / cos(Theta);rOfYuanzhu = 0.5 * D;xLeft = sqrt(R2-rOfYuanzhu*rOfYuanzhu);hOfQiuque = R - xLeft;xRight = L + hOfQiuque - R;return integral(f,-hOfQiuque,L+hOfQiuque);
}int main(){//freopen("1.txt","r",stdin);//freopen("2.txt","w",stdout);while(5==scanf("%lf%lf%lf%lf%lf",&D,&L,&R,&T,&H)){D /= 1E3, L /= 1E3, R /= 1E3,T /= 1E3, H /= 1E3;R2 = R * R;printf("%.3f\n",1E3*proc());}return 0;
}

直接计算的话,精度合适的范围很窄,不合适的话,要么就T,要么就WA。

辛普森方法

要注意写成分段积分的形式,因为如果整个积分的话,有可能存在起点、中点、终点均为000的情况,但起点到中点之间却有一小段体积。另外,递归的时候epsepseps不要乘0.50.50.5,否则会超时。直接设定一个值比较好。这是CF上能够AC的。

#include <bits/stdc++.h>
using namespace std;double const EPS = 1E-1;
double const PI = acos(-1.0);
double const INF = 1E100;inline int sgn(double x){return x>EPS?1:(x<-EPS?-1:0);}
inline bool is0(double x){return 0==sgn(x);}
inline bool isEq(double x,double y){return is0(x-y);}
inline double myasin(double x){if(x<-1.0)x=-1.0;else if(x>1.0)x=1.0;return asin(x);
}
inline double myacos(double x){if(x<-1.0)x=-1.0;else if(x>1.0)x=1.0;return acos(x);
}double simpson(double(*f)(double),double a,double b){double mid = ( a + b ) * 0.5;return (b-a)*(f(a)+f(b)+4.0*f(mid)) / 6.0;
}
//自适应辛普森积分的递归调用
double asr(double(*f)(double),double a,double b,double eps,double ans){double mid = ( a + b ) * 0.5;double lans = simpson(f,a,mid);double rans = simpson(f,mid,b);//精度够直接返回if(fabs(lans+rans-ans)<=eps) return ans;//精度不够递归调用return asr(f,a,mid,eps,lans) + asr(f,mid,b,eps,rans);
}
//自适应辛普森积分,区间[a, b],精度eps,原函数f
double asr(double (*f)(double),double a,double b,double eps){return asr(f,a,b,eps,simpson(f,a,b));
}//计算弓形的高度,半径为r,高度为h
inline double area(double r, double h){if(is0(r)||sgn(h)<=0) return 0.0;if(sgn(h-r-r)>=0) return PI * r * r;double a = r - h;double theta = myacos(a/r);return (theta - 0.5 * sin(theta+theta)) * r * r;
}double D;//球冠底面的直径
double L;//圆柱体的长度
double R,R2;//球冠的球的半径
double T;//倾斜以后,圆柱体母线的高度,即倾斜角就是arcsin(T/L)
double H;//剩下的油,其液面高度,是从圆柱体的底端开始计算
double Theta;
double hOfQiuque,xLeft,xRight,rOfYuanzhu;
double K,B;//y=kx+B;当k是INF表示x=B//计算x处的横截面积,这是一个弓形
double f(double x){double r = rOfYuanzhu;if(x<0){r = sqrt(R2-(x-xLeft)*(x-xLeft));}else if(x>L){r = sqrt(R2-(x-xRight)*(x-xRight));}double y0 = K*x + B;if(isEq(K,INF)) y0 = (x<=B?INF:-INF);return area(r,y0+r-rOfYuanzhu);
}double proc(){if(isEq(T,L)) K = INF, B = H;else Theta = asin(T/L), K = -tan(Theta), B = H / cos(Theta);rOfYuanzhu = 0.5 * D;xLeft = sqrt(R2-rOfYuanzhu*rOfYuanzhu);hOfQiuque = R - xLeft;xRight = L + hOfQiuque - R;return asr(f,-hOfQiuque,0.0,EPS)+ asr(f,0.0,L,EPS)+ asr(f,L,L+hOfQiuque,EPS);
}int main(){/*以下两行注释掉就能在牛客上AC*/freopen("damage.in","r",stdin);freopen("damage.out","w",stdout);//freopen("1.txt","r",stdin);while(5==scanf("%lf%lf%lf%lf%lf",&D,&L,&R,&T,&H)){R2 = R * R;printf("%.6f\n",proc()/1E6);}return 0;
}

Romberg方法

Romberg方法采用了更多段的分段积分。因为在CF上如下数据很难通过。
10000 10000 5000 10000 0
这一组数据本质上就是计算一个球缺的体积,因此其积分曲线的一阶导数变化比较多样,有的地方比较平缓,而有的地方比较陡峭。使用Romberg方法需要将epsepseps设置的比较小,而这又会T其他点。分段积分就比较好。

#include <bits/stdc++.h>
using namespace std;double const EPS = 1E-1;
double const PI = acos(-1.0);
double const INF = 1E100;inline int sgn(double x){return x>EPS?1:(x<-EPS?-1:0);}
inline bool is0(double x){return 0==sgn(x);}
inline bool isEq(double x,double y){return is0(x-y);}
inline double myasin(double x){if(x<-1.0)x=-1.0;else if(x>1.0)x=1.0;return asin(x);
}
inline double myacos(double x){if(x<-1.0)x=-1.0;else if(x>1.0)x=1.0;return acos(x);
}//Romberg积分,求f(x)在[x1,x2]上的定积分
//r[0]表示T序列,r[1]表示S序列,r[2]表示C序列,r[3]表示R序列
double Romberg(double(*f)(double), double x1, double x2,double r[][4]){double h = x2 - x1;int m = 1;r[0][3] = INF;//首先计算T0r[0][0] = 0.5 * h * (f(x1)+f(x2));int const n = 20;for(int i=1;i<n;++i){double *now = *(r + i);double *prev = *(r + i - 1);double h2 = h;h *= 0.5, m <<= 1;//计算Tidouble x = x1 + h;double& sum = now[0];sum = 0.0;for(int j=1;j<m;j+=2){sum += f(x);x += h2;}sum = 0.5 * prev[0] + h * sum;//计算Sinow[1] = (4.0*now[0]-prev[0]) / 3.0;//计算Cinow[2] = (16.0*now[1]-prev[1]) / 15.0;//计算Rinow[3] = (64.0*now[2]-prev[2]) / 63.0;//cout<<i<<" "<<r[i][0]<<" "<<r[i][3]<<endl;//判断if(isEq(prev[3],now[3])) return now[3];}return r[n-1][3];throw runtime_error("XXXXXX");
}//*///计算弓形的高度,半径为r,高度为h
inline double area(double r, double h){if(is0(r)||sgn(h)<=0) return 0.0;if(sgn(h-r-r)>=0) return PI * r * r;double a = r - h;double theta = myacos(a/r);return (theta - 0.5 * sin(theta+theta)) * r * r;
}double D;//球冠底面的直径
double L;//圆柱体的长度
double R,R2;//球冠的球的半径
double T;//倾斜以后,圆柱体母线的高度,即倾斜角就是arcsin(T/L)
double H;//剩下的油,其液面高度,是从圆柱体的底端开始计算
double Theta;
double hOfQiuque,xLeft,xRight,rOfYuanzhu;
double K,B;//y=kx+B;当k是INF表示x=B
double Tmp[1004][4];//计算x处的横截面积,这是一个弓形
double f(double x){double r = rOfYuanzhu;if(x<0){r = sqrt(R2-(x-xLeft)*(x-xLeft));}else if(x>L){r = sqrt(R2-(x-xRight)*(x-xRight));}double y0 = K*x + B;if(isEq(K,INF)) y0 = (x<=B?INF:-INF);return area(r,y0+r-rOfYuanzhu);
}double proc(){if(isEq(T,L)) K = INF, B = H;else Theta = asin(T/L), K = -tan(Theta), B = H / cos(Theta);rOfYuanzhu = 0.5 * D;xLeft = sqrt(R2-rOfYuanzhu*rOfYuanzhu);hOfQiuque = R - xLeft;xRight = L + hOfQiuque - R;int n = 10;double delta = (L+hOfQiuque+hOfQiuque)/n;double x = -hOfQiuque,ans=0.0;for(int i=0;i<n;++i){ans += Romberg(f,x,x+delta,Tmp);x += delta;}return ans;
}int main(){/*以下两行注释掉就能在牛客上AC*/freopen("damage.in","r",stdin);freopen("damage.out","w",stdout);//freopen("1.txt","r",stdin);while(5==scanf("%lf%lf%lf%lf%lf",&D,&L,&R,&T,&H)){R2 = R * R;printf("%.6f\n",proc()/1E6);}return 0;
}

NEERC 2014 D题 Damage Assessment相关推荐

  1. 软件设计师2014上午题基础知识(易错整理)

    软件设计师2014上午题基础知识(易错整理) 2014 上半年 木马程序的客户端运行在攻击者的机器上 海明码检验位计算:有效信息位 + 校验位个数 <= 2^校验位个数 - 1 防火墙工作层次越 ...

  2. NEERC 2014, Eastern subregional contest(汇总)

    之前因为两场比赛时间冲突了,草草水了几发就没再做,整理下! Overview Problem Rank (05:00:00) 0 Comments Setting Favorite Clone   S ...

  3. DELL Software contest 2014 H题 1007 Covering the Corral

    题目: Covering the Corral Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java ...

  4. 寒假作业:COCI 2014/2015题选 题目与题解

    目录 T1 MAFIJA 题目 题解 T2 ZABAVA 题目 题解 T3 KAMP 题目 题解 T4 BOB 题目 题解 T5 SUMA 题目 题解 T6 NORMA 题目 题解 T7 COCI 题 ...

  5. 定积分的计算与辛普森积分及龙贝格积分

    定积分的计算与辛普森积分及龙贝格积分 定积分的计算 辛普森积分公式与自适应辛普森积分 龙贝格积分(Romberg积分) 面积或者体积的计算 hdu1724 [NEERC 2014 D题 Damage ...

  6. C语言单链表实现FCFS算法,2014腾讯实习笔试题

    2014腾讯实习笔试题 1. 关于二叉树,下面说法正确的是() A. 对于N个节点的二叉树,其高度为nlog2n; B. 一个具有1025个节点的二叉树,其高度范围在11~1025之间 C. 二叉树的 ...

  7. 软考高级-系统架构师-案例分析-数据库真题考点汇总

    2010年-2021年(不包括2019年和2020年)涉及到数据库知识考点的有: 2010年题2; 2011年题2; 2012年题5; 2014年题5; 2015年题4,题5; 2017年题4; 20 ...

  8. 2019考研英语二真题词汇整理

    2010真题 swine flu 猪流感 epidemic 传染病,流行病 heightened 提高的,增加的 alert 警惕,警戒 assemble 召集,召开(会议) severity 严重程 ...

  9. 驾校一点通2014电脑版 v1.5 官方版

    驾校一点通2014电脑版 v1.5 官方版 软件大小:6.41MB  软件语言:简体中文 软件类别:应用其他 软件授权:免费版 应用平台:/Win8/Win7/WinXP 是一款模拟驾考软件,该驾校一 ...

最新文章

  1. Android自带的emoji表情的使用
  2. python 条形图_Python数据可视化:基于matplotlib绘制「堆积条形图」
  3. Algorithms学习笔记-Chapter0序言
  4. 启动和停止一个服务,修改服务的启动类型 Start and Stop Service for windows
  5. J2SE:Java环境搭建探究环境变量
  6. 如何通过jQuery动态设置元素CSS的样式,以及HTML中CSS “内联式”、“嵌套式”、“外联式”使用方法
  7. 开发extjs常用的插件
  8. visio 2016安装教程
  9. 一般银行数据结构讲解
  10. 300辆无人车200万公里路测零事故,首次揭秘背后整套安全保障方案
  11. 如何搞定笔记本检测不到wifi,图标,Netkeeper链接不上
  12. 进程互斥锁,队列,IPC进程间通信,生产者与消费者,线程,线程对象的属性,先行互斥锁...
  13. Java线程状态总结
  14. 02 MSC类设备-基础篇(二)
  15. 《Android源码设计模式解析与实战》读书笔记(十四)
  16. idea显示console控制台
  17. python程序设计第一章答案_Python语言程序程序设计-第一章习题解答
  18. 计算机系统概述 —— 硬件系统
  19. Sublime text3配置切换大小写转换
  20. matlab三维可视化,MATLAB中三维数据可视化及应用

热门文章

  1. Intel MIC (至强融核) 安装步骤
  2. 陈艾盐:《春燕》百集访谈节目第三十七集
  3. Ubuntu16.04如何设置自动休眠时间
  4. 在 Linux 终端中自定义 Bash 配色和提示内容
  5. Android应用广告过滤几种方式
  6. 拼多多618手机品牌官旗销量同比增长124%,4000+高价位手机同比增长156%
  7. PHP网站从服务器下载文件到本地
  8. 编译和执行区别 c语言,C语言编译和执行分析
  9. c语言log库,Log4g
  10. Flyme 6将于30日公测 魅蓝Note5有望率先尝鲜