Dying Light
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 492 Accepted Submission(s): 109
Problem Description

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−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.
Input
The 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) , which means the ith mirror's one end is at position (xi,yi) and another end is at ( xi+1 mod n, yi+1 mod n), and its reflectivity is ki .
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).
Then n lines follow. The ith line contains three real numbers xi,yi,ki(−109≤xi,yi≤109;0≤ki≤0.9) , which means the ith mirror's one end is at position (xi,yi) and another end is at ( xi+1 mod n, yi+1 mod n), and its reflectivity is ki .
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).
Output
Output 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
Source
2017 Multi-University Training Contest - Team 9
解题思路:二话不说,直接暴力模拟,每次看当前剩余量是否小于1e-4或者刚好在边界点,否则继续,每次找一个关于当前要打到的直线的对称点,然后对称点和交点作为下一次的入射光线就行。
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-9;
const double judge = 1e-4;
const int maxn = 2000;
struct Point{
double x, y;
Point(double _x = 0, double _y = 0){
x = _x;
y = _y;
}
};
typedef Point Vector;
Vector operator +(Vector A, Vector B) {return Vector(A.x + B.x, A.y + B.y);}//向量加
Vector operator -(Vector A, Vector B) {return Vector(A.x - B.x, A.y - B.y);}//向量减
Vector operator *(Vector A, double p) {return Vector(p * A.x, p * A.y);}//向量的数乘
Vector operator /(Vector A, double p) {return Vector(A.x / p, A.y / p);}//向量的数除
Vector operator -(Vector A) {return Vector(-A.x, -A.y);}//向量的取反
int dcmp(double x)
{
if(fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
bool operator == (const Point& a, const Point& b) {
return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
double Cross(Vector A, Vector B)//求解向量叉积
{
return A.x * B.y - A.y * B.x;
}
double Dot(Vector A, Vector B)//求解向量数量积
{
return A.x * B.x + A.y * B.y;
}
double xmulti(Point p, Point a, Point b)//求向量pa叉乘pb
{
return (a.x - p.x) * (b.y - p.y) - (a.y - p.y) * (b.x - p.x);
}
struct Line{
Point p1;
Point p2;
double kk;
Line(Point _p1, Point _p2){
p1 = _p1;
p2 = _p2;
kk = 0;
}
Line(){
p1 = Point(0, 0);
p2 = Point(0, 0);
}
};
bool line_segment(Line l1, Line l2)//直线l1与线段l2是否相交
{
Point p1 = l1.p1;
Point p2 = l1.p2;
Point p3 = l2.p1;
Point p4 = l2.p2;
Vector v1 = p2 - p1;
Vector v2 = p3 - p1;
Vector v3 = p4 - p1;
double d1 = Cross(v2, v1);
double d2 = Cross(v3, v1);
if(dcmp(d1) * dcmp(d2) <= 0) return true;
else return false;
}
typedef Line seg;
int line_loc(Line l1, Line l2)//判断直线的位置关系,1为平行,0为重合,-1为相交
{
Point p1 = l1.p1;
Point p2 = l1.p2;
Point p3 = l2.p1;
Point p4 = l2.p2;
Vector v1 = p2 - p1;
Vector v2 = p4 - p3;
Vector v3 = p3 - p1;
double d1 = Cross(v1, v2);
double d2 = Cross(v1, v3);
if(dcmp(d1) == 0 && dcmp(d2) == 0) return 0;//重合
else if(dcmp(d1) == 0) return 1;
else return -1;
}
Point seg_intersecting(Line l1, Line l2)//求两相交的直线(线段也一样)的交点
{
Point A = l1.p1;
Point B = l1.p2;
Point C = l2.p1;
Point D = l2.p2;
double _x, _y;
_x = (xmulti(A, B, D) * C.x - xmulti(A, B, C) * D.x) / (xmulti(A, B, D) - xmulti(A, B, C));
_y = (xmulti(A, B, D) * C.y - xmulti(A, B, C) * D.y) / (xmulti(A, B, D) - xmulti(A, B, C));
return Point(_x, _y);
}
Point point_line(Line l, Point p)//点p关于直线l的对称点
{
Point p1 = l.p1;
Point p2 = l.p2;
double _x, _y;
if(dcmp(p1.x - p2.x) == 0)//l斜率不存在
{
_x = 2 * p1.x - p.x;
_y = p.y;
}
else if(dcmp(p1.y - p2.y) == 0)//l斜率为0
{
_x = p.x;
_y = 2 * p1.y - p.y;
}
else
{
double k1 = (p1.y - p2.y) / (p1.x - p2.x);
double b1 = p1.y - k1 * p1.x;
double k2 = -1 / k1;
double b2 = p.y - k2 * p.x;
_x = (b2 - b1) / (k1 - k2);
_y = k2 * _x + b2;
}
return Point(2 * _x - p.x, 2 * _y - p.y);
}
int n;
double x[maxn], y[maxn], k[maxn];
Line L[maxn];
double vx, vy;
int main()
{
while(~scanf("%d", &n))
{
for(int i = 1; i <= n; i++)
{
scanf("%lf%lf%lf", &x[i], &y[i], &k[i]);
}
scanf("%lf%lf", &vx, &vy);
for(int i = 1; i <= n; i++)
{
if(i == n)
{
L[i].p1 = Point(x[i], y[i]);
L[i].p2 = Point(x[1], y[1]);
L[i].kk = k[i];
}
else
{
L[i].p1 = Point(x[i], y[i]);
L[i].p2 = Point(x[i + 1], y[i + 1]);
L[i].kk = k[i];
}
}
int ans = 0;
double Lb = 1.0;
vx *= 0.5;
vy *= 0.5;//避免起始点刚好在一条直线上,不好求关于直线的对称点
Vector dir = Point(vx, vy);
int now;//当前线的编号
Point xx;//交点
Point yy;//对称点
Line l0;
l0.p1 = Point(0, 0);
l0.p2 = dir;
while(fabs(Lb) > judge)
{
if(ans == 0)//起始状态
{
for(int i = 1; i <= n; i++)
{
if(line_segment(l0, L[i]))
{
xx = seg_intersecting(l0, L[i]);
Vector t = xx - dir;
double tt = Dot(t, dir);
if(dcmp(tt) >= 0)
{
ans++;
now = i;
yy = point_line(L[i], dir);
//dir = xx - yy;
l0.p1 = xx;
l0.p2 = yy;
break;
}
}
}
}
else
{
for(int i = 1; i <= n; i++)
{
if(i != now)
{
if(line_segment(l0, L[i]))
{
Point temp = seg_intersecting(l0, L[i]);
ans++;
now = i;
l0.p1 = temp;
l0.p2 = point_line(L[i], xx);
xx = temp;
break;
}
}
}
}
Lb = Lb * L[now].kk;
if(xx == L[now].p1 || xx == L[now].p2) break;
}
printf("%d\n", ans);
}
return 0;
}