hdu5114 Collision [模拟]

Description

给定一个x*y的矩形,矩形里有两个小球,它们初始的速度都是(1, 1),即向右上方。碰壁后会反弹(墙壁为x=0,x=n,y=0,y=m这4条直线),问这两个小球能否相遇,输出相遇的坐标或"Collision will not happen."

Input

第一行一个整数T,表示数据的组数。
每组数据第一行两个整数x,y,表示矩形的长和宽。
第二行4个整数x1, y1, x2, y2,表示这两个小球的初始坐标。

Output

对于每一组数据,第一行输出“Case #x:”,x是数据的编号(从1开始)。
第二行输出两个1位小数,表示两小球相遇的坐标,或者输出“Collision will not happen.”,如果两小球永远不能相遇的话。

Sample Input

3
10 10
1 1 9 9
10 10
0 5 5 10
10 10
1 0 1 10

Sample Output

Case #1:
6.0 6.0
Case #2:
Collision will not happen.
Case #3:
6.0 5.0

Solution

模拟两个小球的运动,当然不能一步一步走,必定会T,只能一段一段地模拟,即:

  • 分别求出两小球到达墙壁的距离,设分别为 dist1,dist2 ,
    接下来两小球要走的距离是 min(dist1,dist2)
  • 判断在这段路程中两小球是否相遇,如果是则输出并返回。
  • 使小球移动,并重复此过程。如果重复了很多次还不能相遇则return false。

说起来简单其实很恶心,我会说我调了一个晚上吗?

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <utility>

#define pii pair<int, int>
#define mp(a, b) make_pair(a, b)
#define getb(x, y, k) (y - (k * x))
#define getx(k1, b1, k2, b2) ((b1 - b2) / (k2 - k1))
#define gety(k, x, b) (k * x + b)
#define getk(p) (p & 1) ? 1 : -1
#define move(nax, nay, nbx, nby) ax = nax, ay = nay, bx = nbx, by = nby;
#define eps 1e-8

using namespace std;

int T, n, m;
int ax, ay, bx, by;
int pa, pb; // a和b的方向。1:右上,2:右下,3:左下,4:左上

bool check(int da, int db, int px, int py) {
    if (fabs(da - db) > eps) return false;
    if (px < -eps || py < -eps || px > n + eps || py > m + eps) return false;
    if (fabs(ax - bx) < eps && pa + pb != 5) return false;
    if (fabs(ay - by) < eps && pa + pb == 5) return false;
    return true;
}

void change(int x, int y, int &p) {
    if (x == n) p = (p == 1) ? 2 : ((p == 4) ? 3 : p);
    if (y == m) p = (p == 1) ? 4 : ((p == 2) ? 3 : p);
    if (!x) p = (p == 2) ? 1 : ((p == 3) ? 4 : p);
    if (!y) p = (p == 3) ? 2 : ((p == 4) ? 1 : p);
}

int getdist(int x, int y, int pos) {
    switch(pos) {
        case 1 : return min(n - x, m - y);
        case 2 : return min(x, m - y);
        case 3 : return min(x, y);
        case 4 : return min(n - x, y);
    }
}

pii next_pos(int x, int y, int pos, int dist) {
    int dx, dy;
    if (pos == 1) dx = dy = 1;
    else if (pos == 2) dx = -1, dy = 1;
    else if (pos == 3) dx = dy = -1;
    else dx = 1, dy = -1;
    return mp(x + dx * dist, y + dy * dist);
}

bool solve() {
    int cnt = 0;
    while (cnt++ <= 1000000) {
        change(ax, ay, pa), change(bx, by, pb);
        int dist1 = getdist(ax, ay, pa);
        int dist2 = getdist(bx, by, pb);
        int dist = min(dist1, dist2);
        // na,nb是移动后两小球的坐标
        pii na = next_pos(ax, ay, pa, dist);
        pii nb = next_pos(bx, by, pb, dist);
        // k,b是直线方程
        int ka = getk(pa);
        int kb = getk(pb);
        int ba = getb(ax, ay, ka);
        int bb = getb(bx, by, kb);
        if (ka == kb && ba == bb && pa != pb || (ax == bx && ay == by)) {
            double px = (double(ax) + double(bx)) / 2.0;
            double py = (double(ay) + double(by)) / 2.0;
            printf("%.1lf %.1lf\n", px, py);
            return true;
        } else if (ka != kb) {
            double px = getx(double(ka), double(ba), double(kb), double(bb));
            double py = gety(ka, px, ba);
            double da = abs(px - ax);
            double db = abs(px - bx);
            if (check(da, db, px, py)) {
                printf("%.1lf %.1lf\n", px, py);
                return true;
            }
        }
        move(na.first, na.second, nb.first, nb.second);
    }
    return false;
}

int main() {
    // freopen("c.in", "r", stdin);
    scanf("%d", &T);
    for (int cas = 1; cas <= T; cas++) {
        printf("Case #%d:\n", cas);
        scanf("%d %d", &n, &m);
        scanf("%d %d %d %d", &ax, &ay, &bx, &by);
        pa = pb = 1;
        if (!solve()) printf("Collision will not happen.\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值