sgu283:Mechanics(计算几何)

时间:2022-06-01 20:06:30

题目大意:
       给你平面上两个圆 (x1,y1),(x2,y2) ,以及它们的质量 m1,m2 和速度 v1,v2
       碰撞过程中不考虑能量损失。
       求出在时刻 t 的两圆坐标和速度。

分析:
       首先我们很容易解个方程求出碰撞时间。问题就是如何计算碰撞后的速度。
       设碰撞时两圆圆心为 A,B ,将 v1,v2 根据 AB 正交分解为垂直的 law1,law2 ,和共线的 x,y ,即 v1=law1+x,v2=law2+y 。那么根据动量守恒和能量守恒,碰撞后只有 x,y 会改变,我们可以列出两个方程:
                       {m1x+m2y=m1x+m2ym1v21+m2v22=m1(law21+x2)+m2(law22+y2)
       解出来就是 x=((m1m21)x+2y)/(1+m1m2),y=x+xy
       然后就没有然后了 ...

AC code:

#include <cstdio>
#include <cmath>
#include <algorithm>
#define sqr(x) ((x)*(x))
typedef double DB;
using namespace std;

const DB eps = 1e-9;

struct pot
{
    DB x, y;
    pot() {x = y = 0;}
    pot(DB _x, DB _y):x(_x),y(_y){}
    void read() {scanf("%lf%lf", &x, &y);}
    void print() {printf("%.3lf %.3lf", x, y);}

    friend pot operator + (const pot &a, const pot &b) {return pot(a.x+b.x, a.y+b.y);}
    friend pot operator - (const pot &a, const pot &b) {return pot(a.x-b.x, a.y-b.y);}
    friend pot operator * (const pot &a, DB k) {return pot(a.x*k, a.y*k);}
    friend pot operator / (const pot &a, DB k) {return pot(a.x/k, a.y/k);}
    friend DB operator * (const pot &a, const pot &b) {return a.x*b.x+a.y*b.y;}
    friend DB operator ^ (const pot &a, const pot &b) {return a.x*b.y-a.y*b.x;}
    DB size() {return sqrt(sqr(x)+sqr(y));}

}p1, v1, p2, v2;
DB r1, r2, m1, m2, t;
DB bump_t;

int sign(DB x)
{
    if(x < -eps) return -1;
    else return x > eps;
}

bool bump()
{
    DB a, b, c, d, e;
    DB A, B, C;
    a = p1.x-p2.x, b = v1.x-v2.x;
    c = p1.y-p2.y, d = v1.y-v2.y;e = r1+r2;
    A = sqr(b)+sqr(d), B = 2*(a*b+c*d), C = sqr(a)+sqr(c)-sqr(e);
    if(sign(A) == 0)
    {
        if(sign(-C/B) < 0) return false;
        else 
        {
            bump_t = -C/B;
            return true;
        }
    } 
    else if(sign(sqr(B)-4*A*C) <= 0) return false;
    else
    {
        DB u, v;
        u = -B/(2*A), v = sqrt(sqr(B)-4*A*C)/(2*A);
        if(sign(u+v) < 0) return false;
        else if(sign(u-v) < 0) bump_t = u+v;
        else bump_t = u-v;
        return true;
    }
}

void solve2(DB t)
{
    p1 = p1+v1*t;
    p2 = p2+v2*t;
    p1.print(), putchar(' '), v1.print(), puts("");
    p2.print(), putchar(' '), v2.print(), puts("");
}

void solve1(DB t)
{
    pot A, B, par, x, y, _x, _y;
    pot law1, law2, _v1, _v2;
    A = p1+v1*bump_t, B = p2+v2*bump_t, par = B-A;
    x = par*(v1*par/sqr(par.size())), y = par*(v2*par/sqr(par.size()));
    law1 = v1-x, law2 = v2-y;
    _x = (x*(m1/m2-1)+y*2)/(1+m1/m2), _y = x+_x-y;
    _v1 = law1+_x, _v2 = law2+_y;
    p1 = A, p2 = B, v1 = _v1, v2 = _v2;
    solve2(t-bump_t);
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif

    p1.read(), v1.read(), scanf("%lf%lf", &r1, &m1);
    p2.read(), v2.read(), scanf("%lf%lf", &r2, &m2);
    scanf("%lf", &t);
    if(bump())
    {
        if(sign(t-bump_t) > 0)
            solve1(t);
        else solve2(t);
    }
    else solve2(t);

    #ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    #endif
    return 0;
}