小球碰撞(NOIPD2T1难度)

来源:互联网 发布:广东利为网络和多益 编辑:程序博客网 时间:2024/05/20 23:57



   这是我们今天早上模拟测试中最水的一道。题应该是我们老师自己出的,在网上没有搜到。刚学完弹性碰撞的我看到这题莫名的亲切。。。

看到这题的第一反应就是刘汝佳蓝书第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 200using 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;}