这是我们今天早上模拟测试中最水的一道。题应该是我们老师自己出的,在网上没有搜到。刚学完弹性碰撞的我看到这题莫名的亲切。。。
看到这题的第一反应就是刘汝佳蓝书第5页蚂蚁爬木棍那题。有一个思想非常关键——无论这个球怎么碰撞,他的相对位置不会改变
例如,初始坐标为最前面的球,无论发生多少次碰撞,他的位置也是第一个。
这样就可以以初始坐标排序,在结构体中记录该球编号,输出答案时双重循环按照编号顺序输出答案即可
蚂蚁那题单位时间只移动1cm,就是速度为1或者-1,而这题速度不同;蚂蚁那题碰撞后速度大小不改变,可以直接交换,而这题....
枚举当前最先碰撞的球,并算出该时间,并按此移动所有的球。
不用像那题一样交换蚂蚁啦,毕竟N<=10
为什么N<=10呢?其实我觉得N<=10000都可以做
老师说,这是因为n个球最多碰撞2的n次方次.这是物理证明。。
个人觉得这是模拟的一道好题
记得sgn 不然0.000000...是大于0的。。
附上代码及测试数据
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 200
using namespace std;
const int inf=0xfffffff/2;
int N,t;
struct node
{
double x;
double v;
double m;
int timee;
}a[maxn];
int compare(const node w1,const node w2){
return w1.x<w2.x;
}
double T[maxn];
double total;
const double eps=1e-5;
int sgn(double x)
{
if (fabs(x)<=eps) return 0;
if (x>0) return 1;
else return -1;
}
void deal(int x1,int x2)
{
double v1=((a[x1].m-a[x2].m)*a[x1].v+2*a[x2].m*a[x2].v)/(a[x1].m+a[x2].m);
double v2=((a[x2].m-a[x1].m)*a[x2].v+2*a[x1].m*a[x1].v)/(a[x1].m+a[x2].m);
a[x1].v=v1;a[x2].v=v2;
}
int main()
{
//freopen("c.in.txt","r",stdin);
//freopen("c.out","w",stdout);
cin>>N>>t;
for(int i=1;i<=N;i++){
cin>>a[i].x>>a[i].v>>a[i].m;
a[i].timee=i;
}
sort(a+1,a+N+1,compare);
while(1){
memset(T,0,sizeof(T));
for(int i=1;i<N;i++)
{
double X=a[i+1].x-a[i].x;
if(sgn(a[i+1].v)>0&&sgn(a[i].v)<0)T[i]=inf;
else if(sgn(a[i+1].v)*sgn(a[i].v)>0){
if(sgn(a[i].v)<=sgn(a[i+1].v))T[i]=inf;
else T[i]=X/fabs((fabs(a[i].v)-fabs(a[i+1].v)));
}
else if(sgn(a[i+1].v)<0&&sgn(a[i].v)>0)
T[i]=X/(fabs(a[i].v)+fabs(a[i+1].v));
}
double minn=inf*1.0;
for(int i=1;i<N;i++)
if(T[i]<minn){minn=T[i];}
int bj2=0;
if(total+minn>=t){minn=t-total;bj2=1;}
for(int i=1;i<=N;i++)
a[i].x+=minn*a[i].v;
if(bj2)break;
total+=minn;
for(int i=1;i<N;i++)
if(a[i+1].x-a[i].x<0.001)
deal(i,i+1);
}
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
if(a[j].timee==i)
printf("%.3lf\n",a[j].x);
return 0;
}