zoukankan      html  css  js  c++  java
  • bzoj1094[ZJOI2007]粒子运动 计算几何

    1094: [ZJOI2007]粒子运动

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 658  Solved: 164
    [Submit][Status][Discuss]

    Description

      阿Q博士正在观察一个圆形器皿中的粒子运动。不妨建立一个平面直角坐标系,圆形器皿的圆心坐标为(x0, y0
    ),半径为R。器皿中有若干个粒子,假设第i个粒子在时刻0的位置为(xi, yi),速度为(vxi,vyi)(注:这是一个
    速度向量,若没有发生碰撞,t时刻的位置应该是(xi + t * vxi, yi + t * vyi) )。假设所有粒子的运动互不干
    扰;若某个粒子在某个时刻碰到了器皿壁,将发生完全弹性碰撞,即速度方向按照碰撞点的切线镜面反射,且速度
    大小不变(如图)。认为碰撞是瞬间完成的。

      尽管碰撞不会影响粒子的速率,但是粒子却会受到一定的伤害,所以若某一个粒子碰撞了k次器皿壁,那么在
    第k次碰撞时它便会消亡。 出于研究的需要,阿Q博士希望知道从时刻0到所有粒子都消亡这段时间内,所有粒子之
    间的最近距离是什么。你能帮助他么?

    Input

      第一行包含三个实数,分别为x0, y0, R,即圆形器皿的圆心坐标及半径。第二行包含两个正整数N, k,分别
    表示粒子的总数与消亡碰撞次数。接下来N行每行四个实数,分别为xi, yi, vxi , vyi,保证(xi, yi)都在圆内且
    (vxi, vyi)非零。

    Output

      仅包含一个实数,即所有粒子的历史最近距离,精确到小数点后三位。

    Sample Input

    0 0 10
    2 10
    0 -5 0 1
    5 0 1 0

    Sample Output

    7.071

    HINT

      对于所有的数据,2 ≤N ≤100。1≤k ≤100。 请注意实数精度问题。

    暴力枚举两个点,判断它们在每一时刻的最短距离
    两个点的运动其实是分段的,每当一个点碰边就重新划分一段,最多可能有2*k段
    每次碰边后重新计算路线,计算方式看这个博客http://blog.csdn.net/lych_cys/article/details/50785713

     1 #include<bits/stdc++.h>
     2 #define N 105
     3 using namespace std;
     4 int n,m,k;double t1,t2,r,c[N][N];
     5 struct point{
     6     double x,y;
     7     point operator + (const point &b)const{return (point){x+b.x,y+b.y};}
     8     point operator * (const double &b)const{return (point){x*b,y*b};}
     9     point operator - (const point &b)const{return (point){x-b.x,y-b.y};}
    10 }o;
    11 struct line{point p,v;}a[N][N];
    12 double dot(point a,point b){return a.x*b.x+a.y*b.y;}
    13 double crs(point a,point b){return a.x*b.y-a.y*b.x;}
    14 double solve(int i,int j,int p1,int p2){
    15     point v1=a[i][p1].v-a[j][p2].v,v2=(a[i][p1].p-a[i][p1].v*c[i][p1])-(a[j][p2].p-a[j][p2].v*c[j][p2]);
    16     double u=dot(v1,v1),v=2*dot(v1,v2),w=dot(v2,v2),t;
    17     if(!u){
    18         if(v>0)t=t1;else t=t2;
    19         return sqrt(w+t*v);
    20     }
    21     else{
    22         t=-v/(2*u);
    23         if(t<t1)t=t1;if(t>t2)t=t2;
    24         return sqrt(t*t*u+v*t+w);
    25     }
    26 }
    27 int main(){
    28     scanf("%lf%lf%lf",&o.x,&o.y,&r);
    29     scanf("%d%d",&n,&m);
    30     double u,v,w,t;point p,q,nm;
    31     for(int i=1;i<=n;i++){
    32         scanf("%lf%lf%lf%lf",&a[i][0].p.x,&a[i][0].p.y,&a[i][0].v.x,&a[i][0].v.y);
    33         for(int j=1;j<=m;j++){
    34             p=a[i][j-1].p-o;q=a[i][j-1].v;
    35             u=dot(q,q);v=dot(p,q)*2;w=dot(p,p)-r*r;
    36             t=(sqrt(v*v-4*u*w)-v)/2/u;
    37             c[i][j]=c[i][j-1]+t;
    38             a[i][j].p=a[i][j-1].p+a[i][j-1].v*t;
    39             nm=a[i][j].p-o;swap(nm.x,nm.y);nm.x=-nm.x;
    40             a[i][j].v=nm*(dot(nm,a[i][j-1].v)/dot(nm,nm)*2)-a[i][j-1].v;
    41             line tmp=a[i][j];
    42             printf("%.2lf %.2lf %.2lf %.2lf
    ",tmp.p.x,tmp.p.y,tmp.v.x,tmp.v.y);
    43         }
    44     }
    45     double ans=1e10;int p1,p2;
    46     for(int i=1;i<=n;i++)
    47         for(int j=i+1;j<=n;j++){
    48             p1=p2=0;
    49             while(p1<m&&p2<m){
    50                 t1=max(c[i][p1],c[j][p2]);
    51                 t2=min(c[i][p1+1],c[j][p2+1]);
    52                 ans=min(ans,solve(i,j,p1,p2));
    53                 if(c[i][p1+1]<c[j][p2+1])p1++;
    54                 else p2++;
    55             }
    56         }
    57     printf("%.3lf
    ",ans);
    58     return 0;
    59 }
  • 相关阅读:
    NOI2013 树的计数
    拆系数FFT学习笔记
    HAOI2017 八纵八横——线段树分治+线性基
    BJOI2018链上二次求和——线段树
    [bzoj3514]Codechef MARCH14 GERALD07加强版——lct+主席树
    KD-Tree 学习笔记
    SDOI2010 捉迷藏 —— KD-Tree
    HAOI2018染色——容斥
    gitignore 不起作用的解决办法
    reids学习教程
  • 原文地址:https://www.cnblogs.com/wsy01/p/8177042.html
Copyright © 2011-2022 走看看