1. 程式人生 > 實用技巧 >2020杭電多校第三場 H - Triangle Collision - 計算幾何

2020杭電多校第三場 H - Triangle Collision - 計算幾何

Description

給定一個等邊三角形,三個頂點分別為 \((-L/2,0),(L/2,0),(0,\sqrt 3L/2)\)

一束光線從 \((x,y)\) 射出,速度為 \((v_x,v_y)\),遇到牆壁會反射,保證不會射到頂點上

問第 \(k\) 次碰撞的時間

Solution

二分答案,考慮求在已知時間內的碰撞次數

把三角形邊看成是鏡子,問題就轉化為在無限密鋪等邊三角形中的運動

考慮與 \(x\) 軸平行的線,這樣答案為 \(|\lfloor \frac y {\frac {\sqrt 3}{2} L} \rfloor|\)

然後通過繞中心旋轉 \(2\pi /3\) 使得斜邊成為平邊,然後重複上述過程即可

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000005;
const double pi = acos(-1);
const double a = 120*pi/180;
const double d = sqrt(3)/6;

double l;
int k;

struct point
{
    double x,y;

    point operator + (const point &b)
    {
        return {x+b.x, y+b.y};
    }
    point operator * (double k)
    {
        return {k*x,k*y};
    }
} r,v;

point rotate(point p,double a)
{
    point res;
    res.x = p.x*cos(a) - p.y*sin(a);
    res.y = p.x*sin(a) + p.y*cos(a);
    return res;
}

point calc(point p)
{
    p.y -= d*l;
    p = rotate(p,a);
    p.y += d*l;
    return p;
}

int eval(point p)
{
    return abs(floor(2*p.y/sqrt(3)/l));
}

int check(double tim)
{
    int ans=0;
    point t=r+v*tim;
    ans+=eval(t);
    t=calc(t);
    ans+=eval(t);
    t=calc(t);
    ans+=eval(t);
    return ans;
}

void solve()
{
    cin>>l>>r.x>>r.y>>v.x>>v.y>>k;
    double l=0,r=1e9;
    while(r-l>1e-6)
    {
        double mid=(l+r)/2;
        //cout<<"mid="<<mid<<" chk="<<check(mid)<<endl;
        if(check(mid)>=k) r=mid;
        else l=mid;
    }
    cout<<setiosflags(ios::fixed)<<setprecision(8)<<l<<endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
}