(LightOJ - 1323)Billiard Balls(思维)

题目链接:Billiard Balls - LightOJ 1323 - Virtual Judge

题意:就是一开始有个矩形,然后矩形内有一些球,每个球都在运动,运动方向有东南,东北,西南,西北四个方向,举个例子,假如当前球的坐标为(x,y),则球沿东北方向运动一秒后就会变成(x+1,y+1),球与球运动过程中可能会发生碰撞,碰撞后两球按原速度沿相反方向运动,问经过k秒后球的位置,按照x为第一优先级,y为第二优先级进行排序,越小越在前。(具体运动方法结合题目中示意图)

我在之前蓝桥杯的一道题目中讲过这种碰撞类问题,两球碰撞后以相同速度反向运动相当于以原速度穿过所碰撞的球体,况且最后是按顺序进行输出,所以无所谓编号,我们这里还用到一个技巧就是我们把斜着运动的方向分解到x轴和y轴,因为这样方便我们进行处理,运动满足复合性,所以我们单独处理每一个方向,最后合起来即为最后位置。我们来看下怎样处理一个方向上的运动,比如说当前球在矩形的长上进行运动,位置为x,长为l,运动时间为t,这个时候我们需要分情况讨论一下(如下图)

第一种情况就是t+x<=l也就是说小球不会与边界发生碰撞,那么我们直接最终位置就是t+x

第二种情况就是t+x<=2*len,也就是说该球只会碰到有边界,不会碰到左边界,这个时候观察图也容易发现,最终位置就是2*len-(x+t)

第三种也是最复杂的,就是该球会多次碰撞左右边界,那么这个时候我们可以先计算第一次碰到左边界所需的时间2*len-pos,用总时间减去这个时间,之后对2*len取余,因为在这个过程中每次经历2*len时间都会回到左边界,然后再次调用原函数即可解决问题。下面附上相应代码:

int UP(int len,int t,int pos)
{
	if(pos+t<=len) return pos+t;
	else if(pos+t<=2*len) return 2*len-(pos+t);
	return UP(len,(t+pos)%(2*len),0);
}

 有了上述基础之后计算相反方向的运动会更加简单,下面分两种情况进行介绍

第一种就是向左移动的距离x<=pos,那么很容易就知道最终位置就是pos-x

若不是上述情况,那么球一定会与左边界发生碰撞,那我们用总时间减去走到左边界所花费的时间作为新的运动所需要花费的时间,且把此时位置设置为左边界所在位置,突然发现小球现在是向右走,这个时候我们就可以调用上面已经写好的函数直接进行运算了

 这个步骤相应代码:

int DOWN(int len,int t,int pos)
{
	if(pos>=t) return pos-t;
	else
		return UP(len,t-pos,0);
}

思路就讲解到这里了,下面可以结合代码好好理解一下

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=1003;
struct point{
	int x,y;
}p[N];
bool cmp(point a,point b)
{
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
int UP(int len,int t,int pos)
{
	if(pos+t<=len) return pos+t;
	else if(pos+t<=2*len) return 2*len-(pos+t);
	return UP(len,(t+pos)%(2*len),0);
}
int DOWN(int len,int t,int pos)
{
	if(pos>=t) return pos-t;
	else
		return UP(len,t-pos,0);
}
int main()
{
	int T;
	cin>>T;
	for(int _=1;_<=T;_++)
	{
		printf("Case %d:\n",_);
		int l,w,n,k;
		scanf("%d%d%d%d",&l,&w,&n,&k);
		char op[5];
		for(int i=1;i<=n;i++)
		{
			int x,y;
			scanf("%d%d%s",&x,&y,op);
			if(op[0]=='N') p[i].y=UP(w,k,y);
			else p[i].y=DOWN(w,k,y);
			if(op[1]=='E') p[i].x=UP(l,k,x);
			else p[i].x=DOWN(l,k,x);
		}
		sort(p+1,p+n+1,cmp);
		for(int i=1;i<=n;i++)
			printf("%d %d\n",p[i].x,p[i].y);
	}
	return 0;
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值