1 条题解
-
0
自动搬运
来自洛谷,原作者为

liaohaoping
**搬运于
2025-08-24 22:02:35,当前版本为作者最后更新于2018-08-14 15:13:00,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
这题数据范围并不大,显然不用什么复杂的优化,求出每个粒子每段(这里简称某粒子两次碰撞之间的部分为一段,包括时刻0到第一次碰撞)的信息就行了,通过观察可发现,只需要处理好以下三个问题(为了方便,我们把所有坐标分别减去圆心的坐标,再把圆心的坐标改为(0,0)):
1、某粒子在某段与圆下次碰撞的位置
2、某粒子在某次碰撞后vx,vy的变化
3、粒子a的某一段与粒子b的某一段(保证某一时刻这两段同时存在)的历史最近距离
先看问题1,若此段起始点为(stx,sty),速度为(vx,vy),设碰撞时间为t,则(stx+vx·t)²+(sty+vy·t)²=r² → stx²+vx²·t²+2·stx·vx·t+sty²+vy²·t²+2·sty·vy·t-r²=0 → (vx²+vy²)·t²+(2·stx·vx+2·sty·vy)·t+(stx²+sty²-r²)=0,我们设a=vx²+vy²,b=2·stx·vx+2·sty·vy,c=stx²+sty²-r²,则t=-b+sqrt(b²-4ac)/2a(舍去小解,小解一定不成立),再通过t算出位置即可。
问题2也不难想,若与圆的碰撞点为(x,y),原速为(x1,x2),反弹后为(x2,y2),不难得出atan2(x2,y2)-atan2(x,y)=atan2(x,y)-atan2(x1,y1)(角相等),即atan2(x2,y2)=2·atan2(x,y)-atan2(x1,y1),设k=x2/y2,则k=tan(2·atan2(x,y)-atan2(x1,y1)),因为速度相同,所以x1²+y1²=x2²+y2²,设z=x1²+y1²,则y2²+k²·y2²=z → (k²+1)·y2²=z → y2=sqrt(x1²+y1²/k²+1),然后通过y2求出x2,需要注意的是,(-x2,-y2)在这里同样成立,我们可以通过带入一个点判断是否在圆内来判断取哪个解。
问题3稍微难一点,为了方便,我们设tt=max(t1,t2)(t1,t2分别为两段开始的时刻),若(x1,y1),(x2,y2)分别为tt时刻两粒子的坐标,(vx1,vy1),(vx2,vy2)分别为两段的速度,y为两粒子间距离的平方,y=((x1+vx1·t)-(x2+vx2·t))²+((y1+vy1·t)-(y2+vy2·t))² → y=((x1-x2)+(vx1-vx2)·t)²+((y1-y2)+(vy1-vy2)·t)²我们设xx=x1-x2,yy=y1-y2,vx=vx1-vx2,vy=vy1-vy2,那么y=(xx+vx·t)²+(yy+vy·t)² → y=xx²+vx²·t²+2·xx·vx·t+yy²+vy²·t²+2·yy·vy·t → y=(vx²+vy²)·t²+(2·xx·vx+2·yy·vy)·t+(xx²+yy²),再设a=vx²+vy²,b=2·xx·vx+2·yy·vy,c=xx²+yy²,然后求出最小值y3=4ac-b²/4a即为历史最近距离,特殊情况特判一下就行了。
我们一开始先用1、2点处理出每个粒子的每一段,再两个两个粒子求历史最近距离,找最小值即为答案。
代码
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; inline int read() { int x=0,w=0;char ch=getchar(); while(ch<'0'||ch>'9')w|=ch=='-',ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return w?-x:x; } struct line{double stx,sty,vx,vy,edt;}; struct particle{line f[110];}p[110]; int n,k;double r,z=0.000000001; inline void get_p(int i,int j,double stx,double sty,double vx,double vy) { p[i].f[j].stx=stx,p[i].f[j].sty=sty,p[i].f[j].vx=vx,p[i].f[j].vy=vy; double a=vx*vx+vy*vy,b=2*stx*vx+2*sty*vy,c=stx*stx+sty*sty-r*r; double t=(-b+sqrt(b*b-4*a*c))/(2*a); p[i].f[j].edt=p[i].f[j-1].edt+t;//求碰撞点 if(j<k) { double edx=stx+vx*t,edy=sty+vy*t; double kk=tan(atan2(edx,edy)*2-atan2(vx,vy)); double vy2=sqrt((vx*vx+vy*vy)/(kk*kk+1)),vx2=kk*vy2; double tt=sqrt(r)/100000/((vx2+vy2)/2);tt=tt<0?-tt:tt; double xx=(edx+vx2*tt),yy=(edy+vy2*tt); if(xx*xx+yy*yy>=r*r)vx2=-vx2,vy2=-vy2; get_p(i,j+1,edx,edy,vx2,vy2);//反弹 } } inline double dis(double x1,double y1,double x2,double y2) { if(x1==x2&&y1==y2)return 0; double x=x1-x2,y=y1-y2; return sqrt(x*x+y*y); } int main() { register double xx,yy;register int i,j,ii,jj; scanf("%lf%lf%lf",&xx,&yy,&r);n=read(),k=read(); for(i=1;i<=n;++i) { double x,y,vx,vy;scanf("%lf%lf%lf%lf",&x,&y,&vx,&vy); x-=xx;y-=yy;p[i].f[0].edt=0;get_p(i,1,x,y,vx,vy); } double ans=1e50; for(i=2;i<=n;++i) { for(j=1;j<i;++j) { jj=1; for(ii=1;ii<=k;++ii)//第一个粒子处于第ii段 { --jj; while(p[i].f[ii].edt>p[j].f[jj].edt&&jj<k)//判断为了使有某时刻两段(ii,jj+1)同时存在,ii是否需要++ { ++jj; double t1=p[i].f[ii-1].edt,t2=p[j].f[jj-1].edt; double x1=p[i].f[ii].stx,x2=p[j].f[jj].stx,y1=p[i].f[ii].sty,y2=p[j].f[jj].sty; double vx1=p[i].f[ii].vx,vx2=p[j].f[jj].vx,vy1=p[i].f[ii].vy,vy2=p[j].f[jj].vy; if(vx1==vx2&&vy1==vy2)//如果速度,方向相等,进行特殊处理 { double t=max(t1,t2),xx1=x1+vx1*(t-t1),xx2=x2+vx2*(t-t2),yy1=y1+vy1*(t-t1),yy2=y2+vy2*(t-t2); ans=min(ans,dis(xx1,yy1,xx2,yy2)); } else { double xx1=x1+vx1*(t1<t2?t2-t1:0),xx2=x2+vx2*(t1>t2?t1-t2:0),yy1=y1+vy1*(t1<t2?t2-t1:0),yy2=y2+vy2*(t1>t2?t1-t2:0); double vx=vx1-vx2,vy=vy1-vy2;xx=xx1-xx2,yy=yy1-yy2; double a=vx*vx+vy*vy,b=2*xx*vx+2*yy*vy,c=xx*xx+yy*yy; double t=-(b/(2*a)); if(t<0)ans=min(ans,dis(xx1,yy1,xx2,yy2));//如果t<0,取最近的合法值(t=0) else if(t+max(t1,t2)>=p[i].f[ii].edt+z||t+max(t1,t2)>=p[j].f[jj].edt+z)//如果该时刻超出任意一段范围,取最近的合法值 { t=min(p[i].f[ii].edt,p[j].f[jj].edt),xx1=x1+vx1*(t-t1),xx2=x2+vx2*(t-t2),yy1=y1+vy1*(t-t1),yy2=y2+vy2*(t-t2); ans=min(ans,dis(xx1,yy1,xx2,yy2)); } else//否则正常计算 { double d=sqrt((4*a*c-b*b)/(4*a)); ans=min(ans,d); } }//求距离 } } } } printf("%.3lf",ans); return 0; }
- 1
信息
- ID
- 3709
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者