问题描述:
在一个矩形框内长w, 高h,现在在底边某一点举例左端点x位置处有一弹性小球(可视为质点)向右上方45°发射,碰撞忽略能量损耗,继续45°弹出,输出在前n次碰撞到底边时每次碰撞的位置。
首先说一种比较繁琐的思路:
碰撞本身是一个过程,我们只需要将所有的可能性考虑到位就好,首先,我们定义如下几个变量用来确定当前的状态:
pos 表示当前的位置在哪条边上,我们默认从顶上顺时针分别为1, 2, 3, 4
s1, s2, h1, h2:分别用来表示在横和竖的四条边上的位置,默认以左端点或下端点为0, 左边的竖线代表s1,右边的竖线代表s2,上边的横线为h1, 下边的为h2
direction:用来表示当前的方向,逆时针碰撞还是顺时针碰撞
然后我们就能根据题意确定初始状态:
direction = -1;
pos = 3;
h2 = x;
解决代码如下:
static void ball(int w, int h, int x, int n){
int s1, s2, h1, h2;
s1 = s2 = h1 = h2 = 0;
int direction = -1;
int pos = 3;
int count = 0;
h2 = x;
//要求输出前n次碰撞到底边的位置
while(count != n + 1){
//逆时针
if(direction == -1){
//判断当前位置
if(pos == 1){
//判断是否超越临边的长度
if(h1 > h){
//确定下次的位置(包括在哪条边上,距离端点的位置长度以及下次碰撞的方向)
pos = 3;
h2 = h1 - h;
direction = 1;
continue;
}else{
pos = 4;
direction = -1;
s1 = h - h1;
continue;
}
}else if(pos == 2){
if(h - s2 > w){
pos = 4;
direction = 1;
s1 = s2 + w;
continue;
}else{
pos = 1;
h1 = w - (h - s2);
direction = -1;
continue;
}
}else if(pos == 3){
count ++;
if(count != 1){
System.out.printf("%d ", h2);
}
if(w - h2 > h){
h1 = h2 + h;
pos = 1;
direction = 1;
continue;
}else{
s2 = w - h2;
pos = 2;
direction = -1;
continue;
}
}else{
if(s1 > w){
pos = 2;
s2 = s1 - w;
direction = 1;
continue;
}else{
pos = 3;
h2 = s1;
direction = -1;
continue;
}
}
}else{
//顺时针
if(pos == 1){
if(w - h1 > h){
pos = 3;
h2 = h1 + h;
direction = -1;
continue;
}else{
pos = 2;
s2 = h - (w - h1);
direction = 1;
continue;
}
}else if(pos == 2){
if(s2 > w){
s1 = s2 - w;
pos = 4;
direction = -1;
continue;
}else{
pos = 3;
h2 = w - s2;
direction = 1;
continue;
}
}else if(pos == 3){
//当在底边时要考虑输出
count ++;
//初始位置不计数
if(count != 1){
System.out.printf("%d ", h2);
}
if(h2 > h){
pos = 1;
direction = -1;
h1 = h2 - h;
continue;
}else{
pos = 4;
direction = 1;
s1 = h2;
continue;
}
}else{
if((h -h1) > w){
pos = 2;
direction = -1;
s2 = h - h1 - w;
continue;
}else{
pos = 1;
direction = 1;
h1 = h - s1;
continue;
}
}
}
}
}
还有一种比较有技巧的做法,通过题意我们了解到碰撞是45°的,所以三角形—>等腰,我们能想到每次碰撞回到底边时,竖直方向的位移距离等于水平方向的位移距离(无论是否是碰撞到临边还是对边,无论是顺时针碰撞还是逆时针碰撞),所以我们可以根据这个结论得出:当竖直方向运动2×h距离时就会回到底边,并且底边的位移距离也等于2×h,所以到现在我们就将问题转换到了在底边运动2×h后的位置,我们要考虑到到达两端点后的反向问题。
也就是说我们要在底边滑动2×h后输出当前位置,解决代码如下:
static void ball2(int w, int h, int x, int n){
//记录当前位置
int pos = x;
//记录当前移动的方向
char flag = 'r';
//每次需要移动2 × h的距离
int temp = 2 * h;
//n次
while(n-- != 0){
temp = 2 * h;
while(temp != 0){
if(flag == 'l'){
if(temp > pos){
temp -= pos;
pos = 0;
flag = 'r';
continue;
}else{
pos -= temp;
System.out.printf("%d ", pos);
break;
}
}else{
if(temp > w - pos){
temp -= (w - pos);
pos = w;
flag = 'l';
continue;
}else{
pos += temp;
System.out.printf("%d ", pos);
break;
}
}
}
}
}
========================
两种方法及测试代码汇总如下:
import java.util.Scanner;
/**
* Created by zhuxinquan on 17-3-9.
* 一个矩形内从底边一点开始斜向上45°发出一个小球(直径忽略),然后反弹
* 求在n次碰撞到底边时每次的位置
*/
public class Crash{
static void ball2(int w, int h, int x, int n){
int pos = x;
char flag = 'r';
int temp = 2 * h;
while(n-- != 0){
temp = 2 * h;
while(temp != 0){
if(flag == 'l'){
if(temp > pos){
temp -= pos;
pos = 0;
flag = 'r';
continue;
}else{
pos -= temp;
System.out.printf("%d ", pos);
break;
}
}else{
if(temp > w - pos){
temp -= (w - pos);
pos = w;
flag = 'l';
continue;
}else{
pos += temp;
System.out.printf("%d ", pos);
break;
}
}
}
}
}
static void ball(int w, int h, int x, int n){
int s1, s2, h1, h2;
s1 = s2 = h1 = h2 = 0;
int direction = -1;
int pos = 3;
int count = 0;
h2 = x;
while(count != n + 1){
//逆时针
if(direction == -1){
if(pos == 1){
if(h1 > h){
pos = 3;
h2 = h1 - h;
direction = 1;
continue;
}else{
pos = 4;
direction = -1;
s1 = h - h1;
continue;
}
}else if(pos == 2){
if(h - s2 > w){
pos = 4;
direction = 1;
s1 = s2 + w;
continue;
}else{
pos = 1;
h1 = w - (h - s2);
direction = -1;
continue;
}
}else if(pos == 3){
count ++;
if(count != 1){
System.out.printf("%d ", h2);
}
if(w - h2 > h){
h1 = h2 + h;
pos = 1;
direction = 1;
continue;
}else{
s2 = w - h2;
pos = 2;
direction = -1;
continue;
}
}else{
if(s1 > w){
pos = 2;
s2 = s1 - w;
direction = 1;
continue;
}else{
pos = 3;
h2 = s1;
direction = -1;
continue;
}
}
}else{
//顺时针
if(pos == 1){
if(w - h1 > h){
pos = 3;
h2 = h1 + h;
direction = -1;
continue;
}else{
pos = 2;
s2 = h - (w - h1);
direction = 1;
continue;
}
}else if(pos == 2){
if(s2 > w){
s1 = s2 - w;
pos = 4;
direction = -1;
continue;
}else{
pos = 3;
h2 = w - s2;
direction = 1;
continue;
}
}else if(pos == 3){
count ++;
if(count != 1){
System.out.printf("%d ", h2);
}
if(h2 > h){
pos = 1;
direction = -1;
h1 = h2 - h;
continue;
}else{
pos = 4;
direction = 1;
s1 = h2;
continue;
}
}else{
if((h -h1) > w){
pos = 2;
direction = -1;
s2 = h - h1 - w;
continue;
}else{
pos = 1;
direction = 1;
h1 = h - s1;
continue;
}
}
}
}
}
public static void main(String[] args){
int w, h, x, n;
Scanner in = new Scanner(System.in);
w = in.nextInt();
h = in.nextInt();
x = in.nextInt();
n = in.nextInt();
ball2(w, h, x, n);
}
}