小球碰撞(NOIPD2T1难度)



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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值