M - Billiard Balls LightOJ - 1323

本文介绍了一种模拟多个小球在一个矩形台面上运动的方法。考虑到小球在碰撞时的行为变化,文章提供了一种简化策略,仅关注小球与边界碰撞的情况,并给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

You are given a rectangular billiard board, L and W be the length and width of the board respectively. Unlike other billiard boards it doesn't have any pockets. So, the balls move freely in the board. Assume that initially some balls are in the board and all of them are moving diagonally. Their velocities are same but their direction may be different. When one or more balls bounce off, their position changes but their velocity remains same.

You are given the initial positions of the balls and their directions; your task is to find the position of the balls after K seconds. The board is placed in the 2D plane such that the boundaries are (0, 0), (L, 0), (L, W) and (0, W). The positions of balls are given as 2D co-ordinates and they all lie inside the board. And the directions are given as one of the following {NE, SE, SW, NW}, N, E, S and W denote North, East, South and West respectively. NE means North-East so both x and y are increasing. The balls are so small that their radiuses can be said to be 0. In each second, the balls advance one unit in their direction. Here one unit doesn't mean Euclidean one unit. For example, if the current position of a ball is (x, y) and its direction is NW then in the next second its position will be (x-1, y+1).

When two or more balls bounce off, they may change their directions as shown in the pictures. You can rotate the pictures to get all possible results. Remember that the balls may bounce at non-integer points.

Bouncing on walls

Bounce result between two balls

Bounce result amongst 3 balls and 4 balls


Input

Input starts with an integer T (≤ 25), denoting the number of test cases.

Each case starts with a line containing four integers L, W (5 ≤ W ≤ L ≤ 108), n (1 ≤ n ≤ 1000) and K (1 ≤ K ≤ 108) where n denotes the number of balls in the board. Each of the next n lines contains two integers x y and a string d, where (x, y) (0 ≤ x ≤ L, 0 ≤ y ≤ W) denotes the co-ordinate of the ball and d can be one of {NE, SE, SW, NW} which denotes the direction of the ball respectively. You can safely assume that the balls are placed in different positions initially.

Output

For each case, print the case number in a single line. Then print the position of the balls. Sort the positions first by their x co-ordinate, and order the ones which have same x coordinate by their y coordinates all in ascending order.

Sample Input

2

10 5 6 1

1 4 NW

1 1 SW

9 1 SE

8 3 NE

9 4 NE

7 4 NE

10 5 6 4

1 4 NW

1 1 SW

9 1 SE

8 3 NE

9 4 NE

7 4 NE

Sample Output

Case 1:

0 0

0 5

8 5

9 4

10 0

10 5

Case 2:

3 2

3 3

7 2

7 3

8 3

9 2

题意:给你一个l*w的矩形,有n个小球在里面以四个方向运动,问经过k秒后的坐标,如果两个小球相撞,会以反方向的相同速度运动,具体相撞情况看上方图;

思路:两个小球相撞其实相当于序号变了,但是方向不变,类似于蚂蚁爬树。。。所以不用考虑小球相撞的问题,只用考虑小球与边界撞击的情况就行了。。。;然后我们把小球分为x和y方向的运动,这样问题就变得很容易了;我们先假设小球向正方向运动:如图:                                               ------》

                                                                |_______________|________|

                                                                0                            x                  L

我们发现小球K秒后运动的长度为2L,4L....小球依然在原点x所以我们可以先让k对2L取余,记为ans,再来讨论小球的位置:

1:  如果小球向右运动的距离ans小于L-x,那么此时小球的坐标为x+ans;

2:  如果 ans>L-x的话,那么说明小球会从右边反弹,此时小球的坐标为L-(ans-(L-x)=2L-ans-x;

3:  如果ans>2L-x的话,说明小球会从左边反弹,此时小球的坐标为ans-(2L-x)=ans-2L+x;

再假设小球向负方向运动:如图:                                     《-------

                                                               |_______________|________|

                                                               0                             m              L;



1:  如果小球想左运动的距离ams小于m的话,此时小球的坐标为m-ams;

2: 如果小球向左运动的距离ams大于m的话,小球的坐标为ams-m;

3: 如果ams>L+m的话,小球从右边反弹回来了,此时小球的坐标为L-(ans-(L+m))=2L-ans+m;

然后分东南西北讨论就好了,,,L方向和W方向一样;

下面附上代码:

#include<bits/stdc++.h>
using namespace std;
struct node
{
	int x,y;
	
}p[1010];
bool cmp(node a,node b)
{
	if(a.x==b.x)
		return a.y<b.y;
	return a.x<b.x;
}
int up(int m,int l,int k)
{
	int ans=k%(l*2);
	if(ans>(l-m))
	{
		if(ans>=2*l-m)
			m=ans+m-2*l;
		else 
			m=2*l-ans-m;
	}
	else
		m+=ans;
	return m;
}
int down(int m,int l,int k)
{
	int ans=k%(2*l);
	if(ans>m)
	{
		if(ans>l+m)
			m=2*l-ans+m;
		else
			m=ans-m;
	}
	else m-=ans;
	return m;
}
int main()
{
	int n,l,w,k,t,r=0;
	char a,b;
	cin>>t;
	while(t--)
	{
		memset(p,0,sizeof(p));
		scanf("%d %d %d %d",&l,&w,&n,&k);
		for(int i=0;i<n;i++)
		{
			scanf("%d %d %c%c",&p[i].x,&p[i].y,&a,&b);
			if(a=='N')
				p[i].y=up(p[i].y,w,k);
			else 
				p[i].y=down(p[i].y,w,k);
			if(b=='E')
				p[i].x=up(p[i].x,l,k);
			else 
				p[i].x=down(p[i].x,l,k);
		}
		sort(p,p+n,cmp);
		printf("Case %d:\n",++r);
		for(int i=0;i<n;i++)
			printf("%d %d\n",p[i].x,p[i].y);	
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值