[SHOI2015]激光发生器

激光发生器

题解

我讨厌数学!!!

计算几何,欺负笔者数学差。

好吧,此题貌似有点坑,总之笔者调了半天。

这么小的数据,一看就是模拟。

其实此题可以分为两大版块,一个部分是求交点,挺好写的,还要判断一下在不在线上。

第二个部分是重点,就是该如何反射。

我们可以先求出它与法线的夹角,再将它旋转,使它达到它反射后的方向。

求夹角的可以用向量求夹角的公式:cos_{\varphi }=\frac{x_{1}x_{2}+ y_{1}y_{2}}{\sqrt{x_{1}^{2}+y_{1}^{2}}+\sqrt{x_{2}^{2}+y_{2}^{2}}}

再将它旋转,将向量旋转b角度后的向量为:\left ( x\cdot cos\, b- y\cdot sin\, b ,x\cdot sin\, b+ y\cdot cos\, b\right )

之后,就只需一个一个求就行了。

 蒟蒻的一些奇思妙想

巨佬请跳过这段。

这是笔者这位蒟蒻考试时想的一个奇怪的方法,不过还没实现出来。

我们很容易就可以求出当前的tan\, \alpha,而我们又有二倍角公式:

  • sin\, 2\alpha= 2sin\, \alpha\cdot cos\, \alpha
  • cos\, 2\alpha= 1- 2sin\,^{2} \alpha

与半倍角公式:

  • sin\, \frac{1}{2}\alpha =\pm \sqrt{\frac{1-cos\,\alpha}{2}}
  • cos\, \frac{1}{2}\alpha= \pm \sqrt{\frac{1+cos\, \alpha}{2}}

那么我们是否可以倍增无限逼近sin\, \lambda\alphacos\, \lambda \alpha呢?

因为\left | a \right |\left | b \right |是小于1000的,所以我们可以在log_{a,b}的时间中将其求出,这样来算之后的结果也不会超时呀?

不过笔者太弱了,没打出来。

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 1005
typedef long long LL;
typedef pair<int,int> pii;
typedef pair<double,double> pdd;
#define re register
#define gc() getchar()
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}
template<class _T>
inline bool cmin(_T &a,const _T&b){
	return a>b?a=b,1:0;
}
int n,bt;
const double eps=1e-6,Pi=acos(-1.0),Loli=Pi*0.5;
double abs(double x){return x<-eps?-x:x;}
int sgn(double x){return x<-eps?-1:x>eps;}
struct point{
	double x,y;
	point(){}
	point(double X,double Y):x(X),y(Y){}
	point operator +(const point &b)const{return point(x+b.x,y+b.y);}
    point operator -(const point &b)const{return point(x-b.x,y-b.y);}
    double operator *(const point &b)const{return x*b.y-y*b.x;}
    double operator ^(const point &b)const{return x*b.x+y*b.y;}
    point operator *(const double &b)const{return point(x*b,y*b);}
	inline double norm(){return sqrt(x*x+y*y);}
    friend double ang(point &a,point &b){return acos((a^b)/a.norm()/b.norm());}
    inline point rot(const double &b){
        double s=sin(b),c=cos(b);
        return point(x*c-y*s,x*s+y*c);
    }
}p,v,c;
struct line{
	point p,v;
	line(){}
	line(point a,point b){p=a;v=b-a;}
	friend point cross(const line &a,const line &b){return a.p+a.v*(b.v*(b.p-a.p)/(b.v*a.v));}
	bool onit(const point &b){return !sgn((b-p)*v)&&sgn((b-p)^(b-(p+v)))<0;}
}l[MAXN];
double reflect[MAXN],bet;
signed main(){ 
	scanf("%lf %lf %lf %lf %d",&p.x,&p.y,&v.x,&v.y,&n);
	for(int i=1;i<=n;i++){
		double x,y,xx,yy,a,b;
		scanf("%lf %lf %lf %lf %lf %lf",&x,&y,&xx,&yy,&a,&b);
		l[i]=line(point(x,y),point(xx,yy));reflect[i]=a/b;
	}
	bool flag=false;
	for(int t=1;t<=10;t++){
		double minn=1e18;int id=0;
		for(int i=1;i<=n;i++)
			if(sgn(v*l[i].v)){
	        	c=cross(line(p,p+v),l[i]);
	            if(l[i].onit(c)&&sgn(v^(c-p))>0&&cmin(minn,(c-p).norm()))
					id=i;
        	}
		if(!id)break;
        p=cross(line(p,p+v),l[id]);
        if(!sgn(v^l[id].v))v=v*-1;
        else{
            c=l[id].v;
            if(sgn(c^v)<0)c=c*-1;
            bet=Loli-ang(v,c),bt=sgn(c*v);
            v=c.rot(bt*(bet*reflect[id]-Loli));
        }
		flag=true;printf("%d ",id);
	}
	if(!flag)puts("NONE");
    return 0;
}

谢谢!!!

发布了117 篇原创文章 · 获赞 154 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Tan_tan_tann/article/details/103745214