洛谷 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. 震惊!C++程序真的从main开始吗?99%的程序员都答错了

    嘿,朋友们好啊!我是小康.今天咱们来聊一个看似简单,但实际上99%的C++程序员都答错的问题:C++程序真的是从main函数开始执行的吗? 如果你毫不犹豫地回答"是",那恭喜你,你 ...

  2. 解决kali虚拟机无法联网问题

    解决kali虚拟机无法联网问题 1.排查虚拟机网络连接-检查ipv4设置,确定好手动连接还是DHCP 如图一 2.排查虚拟网络编辑器-网卡配置,确定虚拟机直连外部网络是否为同一网口 如图二 3.排查虚 ...

  3. 【小鼓捣】手搓Verilog-CPU测试全流程自动化

    自动化流程思路 1.C++/Python:生成大量包含指定指令的mips程序(A.asm) 2.命令行:导出该mips程序指令的机器码(A.txt) 3.魔改MARS:产生测试所需的IM.DM存入信息 ...

  4. go 链表操作

    链表的特点和初始化 链表的特点 用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的) 结点 结点(node) 数据域 => 存储元素信息 指针域 => 存 ...

  5. bug|electron-vue 使用 electron-builder 打包,执行 yarn run build 报错原因

    问题 & 解决 官方BUG:tasks 重复: yarn run build yarn run v1.22.22 $ node .electron-vue/build.js && ...

  6. 【Linux】3.2 vi和vim编辑器

    vi 和 vim 三种模式的相互转化图 vim 和 vi 的快捷键键盘一览图 vi和vim编辑器 1. vi和vim的基本介绍 所有Linux系统都会内置vi文本编辑器 vim是vi的升级版,可以主动 ...

  7. ASP.NET 自定义DataTable数据

    using System.Data; //DataTable try {     DataTable dt = new DataTable();     dt.Columns.Add("Bu ...

  8. sql server2008r2其中一张表不能任何操作

    用户的数据库一张高频表,使用select count(*) from t1 竟然一直在转圈,显示开始,而没有end. 找尽原因不得果.把数据库备份后在恢复,可以使用几小时,之后又是老毛病抽风. 用户生 ...

  9. 『Plotly实战指南』--散点图绘制进阶篇

    在数据分析的世界里,散点图是一种极为重要的可视化工具. 它能够直观地展示两个或多个变量之间的关系,帮助我们快速发现数据中的模式.趋势和异常点. 无论是探索变量之间的相关性,还是寻找数据中的潜在规律,散 ...

  10. GStreamer开发笔记(一):GStreamer介绍,在windows平台部署安装,打开usb摄像头对比测试

    前言   当前GStreamer是开源的多媒体框架,其适配后可以支持板卡的硬编码.硬解码,还提供RTSP服务器等功能,降低了音视频开发的门槛(转移到gstreamer配置和开发上了,但是跨平台),瑞芯 ...