LsF is visiting a local amusement park with his friends, and a mirror room successfully attracts his attention. Inside the mirror room, there are n plane mirrors standing vertically on the ground. They are placed end-to-end and face-to-face so that if you overlook the room, you can find a convex hull and the all the reflector surfaces are inside the pattern. The height of the mirror is not important in this problem.
Due to imperfect manufacturing techniques, mirrors can't reflect light without lose of energy. Each mirror has a reflection efficiency k, which means if the incident light's intensity is I, the reflected light's intensity will be reduced to kI. The only exception could happen when the light precisely goes to the two mirrors' junction. In that case, the light will be completely absorbed instantly. Note the laws of reflection of light applies in all other situations, that the angle of incidence equals the angle of reflection.
Now LsF stands inside the mirror hall, and shoots a laser beam paralleled to the ground using his laser pointer. Unfortunately, his laser pointer can only shot laser beams with intensity of 1. What's worse, a laser beam is considered disappeared if its intensity is below 10−410−4
. There's not much magnitude distance between the two numbers.
LsF wants to know how many touches can his laser beam make with mirrors before it disappears.
InputThe first line contains an integer n(3≤n≤1000), indicating the number of mirrors;
Then n lines follow. The ith line contains three real numbers xi,yi,ki(−109≤xi,yi≤109;0≤ki≤0.9)xi,yi,ki(−109≤xi,yi≤109;0≤ki≤0.9)
, which means the ith mirror's one end is at position (xi,yi)(xi,yi)
and another end is at (xi+1xi+1
mod n,yi+1yi+1
mod n), and its reflectivity is kiki
.
Next there are two real numbers Vx,Vy(-109≤Vx,Vy≤109), indicating the initial direction vector of the laser beam.
LsF is standing at the origin (0, 0).
OutputOutput an integer in one line, the number of touches the laser beam could make before it disappears.Sample Input
4 1 2 0.5 -1 0 0.5 1 -2 0.5 3 0 0.5 0 1 4 1 1 0.5 -1 1 0.5 -1 -1 0.5 1 -1 0.5 1 1
Sample Output
14 1
这道题应该算是一道比较入门的计算几何题,仅涉及到矢量,点积,叉积的使用,当然,使用便于理解的方程表达式也是可以做出这道题的,但实际写代码会很麻烦,我一开始尝试用方程式解决,代码就写了一百五十行,但使用计算几何在七十行左右就能解决,在切入题目之前,我们先学习一下计算几何中的几个概念。
坐标:
设坐标P=(x1,y1),Q=(x2,y2)。
则P,Q表示一个固定的位置。
矢量:
设矢量S1=(x3.y3),S2=(x4,y4)。
矢量表示相对距离。
如S1+P=(x1+x3,y1+y3)。
则得到一个固定的点。
点积:
两个矢量的点积是一个数,大小等于这两个矢量的模的乘积再乘以它们夹角的余弦。
如S1*S2=x3*x4+y3*y4=|S1|*|S2|*cos<S1,S2>。
点积的意义在于可以判断两个向量之间的方向关系(大于90度或小于90度)。
叉积:
叉积也是一个数,相比点积可以从另一个方面判断向量之间的方向关系(顺时针方向或逆时针方向)。
如S1*S2=x1*y2-x2*y1。
可以知道S2在S1的顺时针方向还是逆时针方向。
这里的有一个右手定则,手指向S1的方向,若叉积大于0,则大拇指向上,反之向下,手心指向的便是b的方向。
在涉及到更为复杂的问题前,这些概念已经足够解决这道题目了。
下面讲题意,题目给你n个点,告诉每个点的坐标和它的反射率,每个点连接到下一个点形成镜面,光会在镜面上反射,当光反射后亮度低于1e-4或无法反射时,输出光反射的次数。
分析数据后可以直接暴力判断光与每个镜面是否相交,使用叉积便可以得知光与镜面是否相交,再用点积判断镜面是否在光线的正方向上。至于求交点、求反射后的方向,情况略微麻烦一点,实际上相当于求解方程,就不再具体分析了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int MAX=2e3+10;
const double eps=1e-4;
const double mod=1e9+7;
#define INF 0x7fffffff
#define ll long long
#define edl putchar(' ')
#define useit ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define mst(a) memset(a,0,sizeof(a))
#define mstn(a,n) memset(a,n,sizeof(a))
struct point{double x,y,k;}a[MAX];
//bool cmp(const num &x, const num &y){return x.v>y.v;}
double cross(point a,point b){return (a.x*b.y-a.y*b.x);}
double dot(point a,point b){return (a.x*b.x+a.y*b.y);}
point build(point a,point b){return (point){a.x-b.x,a.y-b.y};}
point cla(point o,point V,point a,point b)
{
double dx=a.x-b.x;
double dy=a.y-b.y;
double t=((o.x-a.x)*dy-(o.y-a.y)*dx)/(V.y*dx-V.x*dy);
return (point){o.x+V.x*t,o.y+V.y*t};
}
int n;
int main()
{
while(scanf("%d",&n)!=EOF)
{
int time=0;
double light=1.0;
point o={0,0},v;
FOR(i,0,n-1) scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].k);
scanf("%lf%lf",&v.x,&v.y);
while(light>=eps)
{
FOR(i,0,n-1)
{
double go=cross(v,build(a[i],o))*cross(v,build(a[(i+1)%n],o));
if(go<0)
{
point c=cla(o,v,a[i],a[(i+1)%n]);
if(dot(v,build(c,o))<0)continue;
double dx=a[(i+1)%n].x-a[i].x;
double dy=a[(i+1)%n].y-a[i].y;
point nex=(point){o.x-2*dx*(dx*o.x+dy*o.y-c.x*dx-c.y*dy)/(dx*dx+dy*dy),o.y-2*dy*(dx*o.x+dy*o.y-c.x*dx-c.y*dy)/(dx*dx+dy*dy)};
v=build(nex,c);
o=(point){c.x+0.1*v.x,c.y+0.1*v.y};
time++;
light*=a[i].k;
break;
}
else if(go==0)
{
light=0;
time++;
break;
}
}
}
printf("%d ",time);
}
}