洛谷 P3945 三体问题

在物竞dalao的帮助下(简化下?)终于A了此题,于是在他的提议下来喷出题人。

接下来看题。

题意分析

模拟三维空间中\(n\)个星体的运动,求\(Ts\)后\(n\)个星体的坐标。使用微元法,\(dt=0.01s\)。

\(n\le 30,0\le T\le 100\)。

精度要求:\(0.5\%\)。

Solution

以下变量大多都是矢量,就不打箭头了

首先列出我们在小学一年级就学过的万有引力公式

\[F=\frac{GMm}{r^2}
\]

其中\(M,m\)分别是两颗星球的质量,\(r\)是距离。

那么在每时每刻,用\(n\)个星体的质量和位置就可以算出每对星球之间的相互作用力。

设\(F_i\)表示第\(i\)颗星球的受力,则

\[F_i=\sum_{j=1,j\not =i}^n \frac{Gm_im_j}{r^2}=Gm_i\cdot\sum_{j=1,j\not =i}^n \frac{m_j}{r^2}
\]

那么,根据牛顿第二定律\(F=am\),这一刻的加速度为

\[a_i=\frac{F_i}{m_i}=G\sum_{j=1;j\not =i}^n \frac{m_j}{r^2}
\]

注意这里前面有个\(\times m_i\),这里有个\(\div m_i\),在程序中可以不用计算了,以保证精度。

然后再用我们在幼儿园就学过的基本运动学公式

\[x=v_0t+\frac12at^2
\\
v=at
\]

当您高高兴兴的算到了这里,觉得这道题配不起它是道蓝题的时候——

欸!我怎么才\(38pts\)?

难道是要先更新\(v\)再更新\(x\)?(即,用\(t+dt\)时刻的速度\(v+a\cdot dt\)当作\(t\)时刻的初速度去计算位移\(x\))

欸!用错误的做法反而分更高了?!(\(40pts\))

再开个\(\texttt{long double}\)试试——

欸!才\(50pts\)?难道要手写实数高精?

看看样例,居然样例跑的都这么吃劲(差距肉眼可见!)

当然也不是控制输出多少位小数的问题,因为错误只会出在\(0.005\)中。

于是我请\(LHQing\)来帮我调这一道题(他以前写过一个物理模拟器),在10min后他过了。

原因是,此题\(std\)认为在\(dt\)中星球做匀速直线运动,速度只会在每个\(dt\)之后改变,即

\[v=at
\\
x=vt
\]

只需要这两个公式,不需要考虑星球在这段\(dt\)中的加速度!

那么,从某种意义上,\(std\)的精度岂不是比我的要劣……

Code

三维矢量

struct vector
{
long double x,y,z;
vector(long double xx=0,long double yy=0,long double zz=0)
{
x=xx,y=yy,z=zz;
}
void clear()
{
x=y=z=0;
}
void in()
{
cin>>x>>y>>z;
}
void out()
{
printf("%Lf %Lf %Lf",x,y,z);
}
vector operator+(const vector& b)const
{
return vector(x+b.x,y+b.y,z+b.z);
}
vector operator+=(const vector& b)
{
x+=b.x;
y+=b.y;
z+=b.z;
return *this;
}
vector operator*(const long double& b)
{
return vector(x*b,y*b,z*b);
}
vector operator*=(const long double& b)
{
x*=b;
y*=b;
z*=b;
return *this;
}
vector operator/(const long double& b)const
{
return vector(x/b,y/b,z/b);
}
}F[100];

星球

struct Star
{
vector pos,v;
long double m;
IL void in()
{
pos.in();
cin>>m;
v.in();
}
IL void out()
{
pos.out();
} }star[100];

计算

for(;T>0;T-=dt)
{
for(int i=1;i<=n;i++) F[i].clear();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) continue;
r=(star[i].pos.x-star[j].pos.x)*(star[i].pos.x-star[j].pos.x)+(star[i].pos.y-star[j].pos.y)*(star[i].pos.y-star[j].pos.y)+(star[i].pos.z-star[j].pos.z)*(star[i].pos.z-star[j].pos.z);
f=G*star[j].m/r;
F[i]+=vector(f*(star[j].pos.x-star[i].pos.x)/sqrt(r),f*(star[j].pos.y-star[i].pos.y)/sqrt(r),f*(star[j].pos.z-star[i].pos.z)/sqrt(r));
}
}
for(int i=1;i<=n;i++)
{
star[i].v+=F[i]*dt;
star[i].pos+=(star[i].v)*dt;
}
}

完整代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<limits.h>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
using namespace std;
const long double G = 6.67408e-11;
const long double dt = 1e-2;
int n;
long double T;
struct vector
{
long double x,y,z;
vector(long double xx=0,long double yy=0,long double zz=0)
{
x=xx,y=yy,z=zz;
}
void clear()
{
x=y=z=0;
}
void in()
{
cin>>x>>y>>z;
}
void out()
{
printf("%Lf %Lf %Lf",x,y,z);
}
vector operator+(const vector& b)const
{
return vector(x+b.x,y+b.y,z+b.z);
}
vector operator+=(const vector& b)
{
x+=b.x;
y+=b.y;
z+=b.z;
return *this;
}
vector operator*(const long double& b)
{
return vector(x*b,y*b,z*b);
}
vector operator*=(const long double& b)
{
x*=b;
y*=b;
z*=b;
return *this;
}
vector operator/(const long double& b)const
{
return vector(x/b,y/b,z/b);
}
}F[100];
struct Star
{
vector pos,v;
long double m;
IL void in()
{
pos.in();
cin>>m;
v.in();
}
IL void out()
{
pos.out();
} }star[100];
int main()
{
cin>>n>>T;
for(int i=1;i<=n;i++) star[i].in();
long double f,r;
for(;T>0;T-=dt)
{
for(int i=1;i<=n;i++) F[i].clear();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) continue;
r=(star[i].pos.x-star[j].pos.x)*(star[i].pos.x-star[j].pos.x)+(star[i].pos.y-star[j].pos.y)*(star[i].pos.y-star[j].pos.y)+(star[i].pos.z-star[j].pos.z)*(star[i].pos.z-star[j].pos.z);
f=G*star[j].m/r;
F[i]+=vector(f*(star[j].pos.x-star[i].pos.x)/sqrt(r),f*(star[j].pos.y-star[i].pos.y)/sqrt(r),f*(star[j].pos.z-star[i].pos.z)/sqrt(r));
}
}
for(int i=1;i<=n;i++)
{
star[i].v+=F[i]*dt;
star[i].pos+=(star[i].v)*dt;
}
}
for(int i=1;i<=n;i++)
{
star[i].out();
cout<<endl;
}
return 0;
}

注意第\(95\)行,\(r\)的定义是\(r^2\),不先开方是为了精度。

以及玄学的物理计算在第\(102,103\)行

喷喷喷

洛谷 P3945 三体问题的更多相关文章

  1. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  2. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  3. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  4. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  5. 洛谷P1710 地铁涨价

    P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交  讨论  题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...

  6. 洛谷P1371 NOI元丹

    P1371 NOI元丹 71通过 394提交 题目提供者洛谷OnlineJudge 标签云端评测 难度普及/提高- 提交  讨论  题解 最新讨论 我觉得不需要讨论O long long 不够 没有取 ...

  7. 洛谷P1538迎春舞会之数字舞蹈

    题目背景 HNSDFZ的同学们为了庆祝春节,准备排练一场舞会. 题目描述 在越来越讲究合作的时代,人们注意的更多的不是个人物的舞姿,而是集体的排列. 为了配合每年的倒计时,同学们决定排出——“数字舞蹈 ...

  8. 洛谷八月月赛Round1凄惨记

    个人背景: 上午9:30放学,然后因为学校举办读书工程跟同学去书城选书,中午回来开始打比赛,下午又回老家,中间抽出一点时间调代码,回家已经8:50了 也许是7月月赛时“连蒙带骗”AK的太幸运然而因同学 ...

  9. 洛谷 P1379 八数码难题 Label:判重&&bfs

    特别声明:紫书上抄来的代码,详见P198 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给 ...

  10. [洛谷OJ] P1114 “非常男女”计划

    洛谷1114 “非常男女”计划 本题地址:http://www.luogu.org/problem/show?pid=1114 题目描述 近来,初一年的XXX小朋友致力于研究班上同学的配对问题(别想太 ...

随机推荐

  1. 记线上+线下培训思想i技巧感悟

    刚刚结束一场线下+线上培训 梳理一下,有几个问题: 1.虽然课件自己过了几遍,同时备注里写了一些提示 ,但是真正讲课的时候基本是没有过程特意去扫备注 注意备注应清晰,写核心关键字 2.分屏过程 需要在 ...

  2. Web前端入门第4问:HTML、CSS、JavaScript 的作用分别是什么?

    HTML.CSS.JavaScript 的核心作用 HTML:网页的骨架 功能:定义页面的内容结构(如按钮.表格.图片). 示例:<button>提交</button> 创建一 ...

  3. 一些Qt样式设计的小积累

    QRadioButton 的设计 QRadioButton分有两个部分,由按钮和背景文字组成. QRadioButton::indicator { ...; // 设置你想要的属性 } QRadioB ...

  4. Qt关于使用QSqlQuary::size()这个函数值返回是-1

    QSqlQuary::size( ) 今天做项目的时候,用Qt连接Oracle数据库,前面都是连接成功,但是用SQL语句去操作数据库的时候,发现老是读不到内容,卡了好久. QSqlQuery Rule ...

  5. 当你在浏览器中输入 google.com 后按下回车发生了什么?

    按下"g"键 接下来的内容介绍了物理键盘和系统中断的工作原理,但是有一部分内容却没有涉及.当你按下"g"键,浏览器接收到这个消息之后,会触发自动完成机制.浏览器 ...

  6. Windows 提权-密码搜寻

    本文通过 Google 翻译 Password Hunting – Windows Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释 ...

  7. 【JVM之内存与垃圾回收篇】直接内存

    直接内存 Direct Memory 不是虚拟机运行时数据区的一部分,也不是<Java 虚拟机规范>中定义的内存区域. 直接内存是在 Java 堆外的.直接向系统申请的内存区间. 来源于 ...

  8. Superfetch/SysMain

    卡的不要不要的 Windows 服务中有一个叫 Superfetch. 现在换了个马甲叫 SysMain 本意是好的,超级预读功能可以帮助大型软件极大提升启动加载时间,但是经常抽风至少我觉得 导致磁盘 ...

  9. MySqlDataAdapter.Fill() 报异常‘给定关键字不在字典中’的解决方案

    MySqlDataAdapter.Fill() 报异常'给定关键字不在字典中'的解决方案 解决办法 升级依赖库 后来发现居然是MySql.Data.dll文件版本问题,我开始使用的是6.2.1.0版本 ...

  10. 学习unigui【19】unidbgrid的Group By This Field汉化

    上面已经将group by this field 汉化. 由于版本的不断更新,不可避免有汉化遗漏.那么说到 如何汉化问题. 根据ExtJSVersion查找你电脑响应目录文件D:\Program Fi ...