目录

  • 引言
  • 具体解法
    • 问题描述
    • 输入
    • 输出
    • 样例输入
    • 样例输出
    • 解题思路
    • 代码实现
  • 总结

引言

高中物理有一个十分经典的问题,即小球碰撞问题。将这个物理问题简化,不考虑能量损耗,且假设每个小球的速度大小与质量都一致,就成为一个经典的算法问题,即给定若干小球的初始位置与速度矢量,计算一段时间后各小球的位置与运动情况。
       这是一个很经典的问题,也已经有了许多C语言的大佬对此题给出了非常巧妙的算法。笔者作为一个C语言新手,还很难超越前人,创造出更巧妙的算法,但想在此给出一种较为繁复甚至有些笨拙,却能通过模拟这个运动过程最终给出答案的暴力解题法。希望我的解法能作为对这个问题算法一个微不足道的补充,也希望能为和我一样的初学者带来启发。同时,笔者也真诚地期待看到此篇文章的前辈们不吝赐教,对我的算法进行批评指正。

具体解法

本问题的核心在于运动过程中小球的相遇,以及碰撞之后方向的改变,而笔者的代码原本是为另一道与此小球碰撞本质相同的问题书写的。为了方便,我将直接以这道与小球碰撞本质相同的问题为例,对此算法进行解释。

问题描述

长度为 L 的直跑道上有 n 个同学,每个同学只会朝南或北两个方向走,速度都为 1 米每秒 。当两个同学相遇时,两个同学将同时转向(转身时间忽略不计)。现给出每个同学的初始位置和运动方向,计算 T 秒后每个同学的位置。(说明:这里指的位置由同学距离跑道北端起点的距离表示,位于最北端的同学位置是 0 ,位于最南端的同学位置是 L 。)

输入

第一行为三个用空格分隔的正整数 L , n , T ( 1 ≤ n ≤ L ≤ e4 , 0 ≤ T ≤ e4 )。
       之后 n 行,每行一个正整数 x (0 ≤ x ≤ L ),表示同学到跑道最北端起点的距离,和一个字母 c 表示初始朝向。 c 只会为 N 或 S , N 表示朝北, S 表示朝南。 保证每位同学的初始位置不同。

输出

输出 n 行,按输入顺序输出每位同学的位置和朝向,中间用一个空格隔开。对于在第 T 秒之前已经走出 TD 线的同学,输出 Finished 。(说明:朝向用字符表示,N 表示朝北,S 表示朝南,Turning 表示正在转身。)

样例输入

10 4 1
1 S
5 S
3 N
10 S

样例输出

2 Turning
6 S
2 Turning
Finished

解题思路

在这个运动过程中,重要因素包括各同学的初始位置和每个同学的速度矢量,其实本题给出数据输入格式时已经将这些这些因素数据化。如果我们把每个同学看做一个对象,将其位置与速度矢量(由于这里速度大小恒为 1 ,因此主要是朝向),赋给这个对象即可。为此,我们可以定义两个数组(字符数组),分别用来记录每位同学的位置和朝向,通过数组(字符数组)的下标实现与每位同学的一一对应。此外,还需定义一个数组表示跑道(相当于数轴)的各个位置坐标。以便判断运动中相遇的情况。
       接下来,就要通过程序运算模拟每位同学的运动,这可以通过对与每位同学一一对应的位置和朝向数组进行操作来实现。但在考虑运动过程中相遇的情况时,如果选 1 为时间间隔,那么相遇就可能发生在每一时间间隔的中间或者末尾。对于发生在中间的相遇,可以直接互换二者的朝向,位置不变;而当相遇发生在,时间间隔末尾时,二者在这一瞬间会“重叠”。这时,一个表示各跑道位置坐标的数组已经不够,还需要再定义一个相同的数组以储存“重叠”的对象。
       在运动结束的瞬间,仍可能发生相遇转身的情况,因此最后还应再对可能的相遇情况进行一次处理。

代码实现

#include<stdio.h>int Position[10100];                                                //以数组Position记录每位同学的位置,数组的下标即同学的编号;
int Record[10100],AnotherRecord[10100];                             //以数组Record记录跑道上每个位置是否有同学,以跑道为x轴,数组的下标即不同位置的坐标;数组AnotherRecord用于位置重叠时的记录;
int op[10100];                                                      //以数组op标记对应同学所作的操作——继续前进或转身,数组的下标即同学的编号;
char Der[10100];                                                    //定义字符数组Der,记录每位同学的前进方向,数组的下标即同学的编号;
int L,n,T;void ChangeDirection(int a,int b)
{char carrier;carrier=Der[a];Der[a]=Der[b];Der[b]=carrier;
}int main()
{int i;int t;                                                          //记录跑道上同学的运动时间;scanf("%d%d%d",&L,&n,&T);for(i=1; i<=n; i++)scanf("%d %c",&Position[i],&Der[i]);                        //录入每位同学的初始位置与运动方向;for(t=1; t<=T; t++)                                            //t的增加代表时间的演进;{for(i=0; i<10010; i++)                                     //初始化数组;{Record[i]=-1;op[i]=0;AnotherRecord[i]=-1;}for(i=1; i<=n; i++){if(Position[i]>=0&&Position[i]<=L){if(Record[Position[i]]==-1)Record[Position[i]]=i;                         //数组Record中对应的数字为-1代表该位置为空,可以直接占据这个位置,并将Record中该点对应的值赋为占据这个点的同学的编号;else{ChangeDirection(i,Record[Position[i]]);AnotherRecord[Position[i]]=i;                  //若该位置有人的话,则两者交换前进方向,位置坐标不变}}else{Position[i]=-1;Der[i]='F';                                        //以'F'表示该同学已走出跑道,走出跑道的同学位置统一标记为-1;}}for(i=1; i<=L; i++)                                        //遍历一次每位同学的运动情况,检查本次运动中是否会有相遇的情况;{if(Position[i]>0){/*注:这里在判断相遇时,由于部分位置可能存在重叠,因此要检查运动的两端是否存在重叠,以及重叠的两个人各自的相遇情况,即4种情况*/if(Record[Position[i]-1]!=-1&&Record[Position[i]]!=-1&&Der[Record[Position[i]-1]]=='S'&&Der[Record[Position[i]]]=='N'&&op[Record[Position[i]-1]]==0&&op[Record[Position[i]]]==0){ChangeDirection(Record[Position[i]-1],Record[Position[i]]);op[Record[Position[i]-1]]=1;op[Record[Position[i]]]=1;}else if(AnotherRecord[Position[i]-1]!=-1&&AnotherRecord[Position[i]]!=-1&&Der[AnotherRecord[Position[i]-1]]=='S'&&Der[AnotherRecord[Position[i]]]=='N'&&op[AnotherRecord[Position[i]-1]]==0&&op[AnotherRecord[Position[i]]]==0){ChangeDirection(AnotherRecord[Position[i]-1],AnotherRecord[Position[i]]);op[AnotherRecord[Position[i]-1]]=1;op[AnotherRecord[Position[i]]]=1;}else if(AnotherRecord[Position[i]-1]!=-1&&Record[Position[i]]!=-1&&Der[AnotherRecord[Position[i]-1]]=='S'&&Der[Record[Position[i]]]=='N'&&op[AnotherRecord[Position[i]-1]]==0&&op[Record[Position[i]]]==0){ChangeDirection(AnotherRecord[Position[i]-1],Record[Position[i]]);op[AnotherRecord[Position[i]-1]]=1;op[Record[Position[i]]]=1;}else if(Record[Position[i]-1]!=-1&&AnotherRecord[Position[i]]!=-1&&Der[Record[Position[i]-1]]=='S'&&Der[AnotherRecord[Position[i]]]=='N'&&op[Record[Position[i]-1]]==0&&op[AnotherRecord[Position[i]]]==0){ChangeDirection(Record[Position[i]-1],AnotherRecord[Position[i]]);op[Record[Position[i]-1]]=1;op[AnotherRecord[Position[i]]]=1;}}}for(i=1; i<=n; i++){if(Der[i]=='S'&&op[i]==0)Position[i]=Position[i]+1;else if(Der[i]=='N'&&op[i]==0)Position[i]=Position[i]-1;}//数组op对应的值为0时表示继续前进,值为1时表示本次转身,不前进;}/*最后一秒末可能存在两位同学正好走到同一位置的情况,因此要再判断一次*/for(i=0; i<10010; i++)Record[i]=-1;for(i=1; i<=n; i++){if(Position[i]>=0&&Position[i]<=L){if(Record[Position[i]]==-1)Record[Position[i]]=i;else if(Record[Position[i]]!=-1){Der[i]='T';Der[Record[Position[i]]]='T';}}else{Position[i]=-1;Der[i]='F';}}for(i=1; i<=n; i++){if(Der[i]=='T')printf("%d Turning\n",Position[i]);else if(Der[i]=='F')printf("Finished\n");elseprintf("%d %c\n",Position[i],Der[i]);}return 0;
}

总结

将一个过程的影响因素参数化,再通过代码运算模拟这个过程,可以实现对部分问题的暴力破解,这实际上也是将真实世界的问题数据化、程序化的过程,对锻炼理性思维有着一定的积极作用。


例题原作者:Inx From BUAA

若干小球碰撞的一种暴力解题法相关推荐

  1. 一个与小球碰撞有关的有趣问题

    -一个与小球碰撞有关的问题 -本人学号:16340300 -本人学院:数据科学与计算机学院 目录 看看这个问题 如何解决 解法 看看这个问题 如图,在光滑水平面上,有一个球A向墙运动,速度垂直于墙面, ...

  2. js 小球碰壁反弹and小球碰撞

    好像好几天没有更博了呢,最近有点变懒了,这样不好,不好~~我们要做热爱学习的好孩子,嘻嘻,今天下午补上... 我们在学习js的时候,一个很经典的案例就是小球的碰壁反弹效果啦~简单的小球碰壁效果可以慢慢 ...

  3. CCF软件认证题 java 201803-2 小球碰撞

    CCF软件认证题 java 201803-2 小球碰撞 问题描述 数轴上有一条长度为L(L为偶数)的线段,左端点在原点,右端点在坐标L处.有n个不计体积的小球在线段上,开始时所有的小球都处在偶数坐标上 ...

  4. IDEA——找不到或无法加载主类的一种暴力解决方法

    IDEA--找不到或无法加载主类的一种暴力解决方法 参考文章: (1)IDEA--找不到或无法加载主类的一种暴力解决方法 (2)https://www.cnblogs.com/jsjliyang/p/ ...

  5. java 圆形碰撞箱_你会使用“碰撞箱”吗?5种你不知道的玩法 甚至能定位死亡方位...

    原标题:你会使用"碰撞箱"吗?5种你不知道的玩法 甚至能定位死亡方位 "碰撞箱"对于萌新来说是个陌生的词,但对于一些玩家来说却是一个生存利器! 一.什么是&qu ...

  6. pygame动画演示小球碰撞

    使用pygame实现动量定理的小球碰撞演示动画 动量定理我们在高中的时候就已经接触过了,是十分重要的物理定理.其中的完全弹性碰撞(机械能守恒)是十分典型的例子,机械能守恒和动量定理两个公式就可以推出小 ...

  7. Canvas+Js制作动量守恒的小球碰撞

    目的:通过js实现小球碰撞并实现动量守恒 canvas我们就不多说了,有用着呢. 我们可以通过canvas画2D图形(圆.方块.三角形等等)3D图形(球体.正方体等待). 当然这只是基础的皮毛而已,c ...

  8. Java反弹球两球相撞_java实现小球碰撞反弹

    java实现小球碰撞反弹 java实现小球碰撞反弹 首先我们要在一个窗口里面显示这个功能,因此引入JFrame类然后创建一个窗口代码如下: JFrame win=new JFrame();//新建窗口 ...

  9. JS实现小球碰撞边界反弹-点击消失(详细解析实现思路)

    本篇文章给大家带来的是原生JS实现小球碰到边界就反弹,点击小球时小球被会销毁,并重新创建一个小球,让小球的数量一直保持在初始的数量,按照思路按步骤进行讲解,只需要源码的小伙伴可以定位到文本末尾直接复制 ...

  10. js小球碰撞js特效

    下载地址 小球碰撞特效.引用test.js文件.我目前做的是10个小球同时出现,你也可以根据你的需要进行修改.如果你想要小球随机出现的话,你只需要把58行的代码解注,然后57行的注释就行了.这个写法还 ...

最新文章

  1. CCNP ONT LAB之PQ WFQ
  2. 网络编程(part9)--socket套接字编程之TCP套接字
  3. 迅雷的声音:摆脱视频产业的经济化困境
  4. C++——override
  5. Leetcode每日一题:26.remove-duplicates-from-sorted-array(删除排序数组中的重复项)
  6. centos安装aria2c_Centos 7 编译安装Aria2
  7. C# 执行文件的根目录 (转)
  8. mysql:多表查询方式
  9. 【数据融合】基于matlab拓展卡尔曼滤波IMU和GPS数据融合【含Matlab源码 1600期】
  10. python计算正方形、立方体、圆、球的面积和体积
  11. Quartus ii安装及使用实验报告
  12. 计算机设计大赛物联网专项赛专栏
  13. 树莓派网易云音乐播放器
  14. 诺基亚pc远程服务器,用远程桌面把win10装进iphone —-40核256G内存的生产力工具随身带...
  15. Win11自动生成文件目录
  16. zblog导航小智收录网导航模板
  17. OPA1611AIDR IC AUDIO 1 CIRCUIT 8SOIC
  18. cache数据库入门教程
  19. python制作gif动画_使用Python代码制作GIF动态图
  20. 腾讯欲全资收购搜狗,目的是什么?

热门文章

  1. Jmeter 面试题
  2. 关于VGGNet网络结构浅谈(主要是VGG16结构)
  3. VGG16网络参数细节
  4. 外螺纹对照表_螺纹螺距对照表
  5. Java密码学原型算法实现——第三部分:双线性对
  6. 药房管理系统 药店管理系统 GITHUB
  7. 算法动画图解(安卓)、排序算法的可视化
  8. 拟合美国人口matlab编码,美国人口数据的阻滞增长模型拟合分析
  9. 单片机外文参考文献期刊_求有关单片机的中英文参考文献
  10. 3ds Max 2012 简体中文版 带注册机32位64位