LA 5007 Detector Placement 模拟
题意:
给出一束光线(射线),和一块三角形的棱镜 以及 棱镜的折射率,问光线能否射到X轴上,射到X轴上的坐标是多少。
分析:
其实直接模拟就好了,注意到题目中说不会发生全反射,所以如果射到棱镜中的话就一定能射出来。
一开始判断一下能否经过棱镜折射,不能的话直接算和X轴有没有交点或者交点的坐标。
- 然后就是根据入射光线T1求入射点P1,注意直线可能和三角形的两条边都有交点,但最近的那个才是入射点。
找到入射点就求法线,算角度,利用折射公式算折射角,求出折射光线T2。 - 第二部分其实和上面的过程是一样的,求出射点,根据公式算出射角,最后求得出射光线。
- 出射光线和X轴求交点,或者没有交点。
上个样例的光路图,仅供参考:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps = 1e-8;
int dcmp(double x) {
if(fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
struct Point
{
double x, y;
void read() { scanf("%lf%lf", &x, &y); }
void print() { printf(" (%.2f, %.2f) \n", x, y); }
Point(double x = 0, double y = 0): x(x), y(y) {}
};
typedef Point Vector;
Point operator + (const Point& A, const Point& B) {
return Point(A.x + B.x, A.y + B.y);
}
Point operator - (const Point& A, const Point& B) {
return Point(A.x - B.x, A.y - B.y);
}
Point operator * (const Point& A, double p) {
return Point(A.x * p, A.y * p);
}
Point operator / (const Point& A, double p) {
return Point(A.x / p, A.y / p);
}
double Dot(const Vector& A, const Vector& B) {
return A.x * B.x + A.y * B.y;
}
double Cross(const Vector& A, const Vector& B) {
return A.x * B.y - A.y * B.x;
}
double Length(Vector A) { return sqrt(Dot(A, A)); }
double Distance(Point A, Point B) { return Length(A - B); }
Vector Normal(Vector v) { return Vector(-v.y, v.x); }
Vector Rotate(Vector A, double rad) {
return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));
}
struct Line
{
Point P;
Vector v;
Line() {}
Line(Point P, Vector v) : P(P), v(v) {}
};
bool OnSegment(Point P, Point a1, Point a2) {
Vector v1 = a1 - P, v2 = a2 - P;
return dcmp(Cross(v1, v2)) == 0 && dcmp(Dot(v1, v2)) < 0;
}
bool isParallel(const Line& A, const Line& B) {
return dcmp(Cross(A.v, B.v)) == 0;
}
Point GetLineIntersection(Line L1, Line L2, double& t)
{
Vector u = L1.P - L2.P;
t = Cross(L2.v, u) / Cross(L1.v, L2.v);
return L1.P + L1.v * t;
}
double u;
Point p[3], s, t;
Line L[3];
int main()
{
Point hehe(0, 0), haha(10, 0);
Line flat(hehe, haha);
int T; scanf("%d", &T);
while(T--) {
s.read(); t.read();
for(int i = 0; i < 3; i++) p[i].read();
scanf("%lf", &u);
L[0] = Line(p[0], p[1] - p[0]);
L[1] = Line(p[1], p[2] - p[1]);
L[2] = Line(p[2], p[0] - p[2]);
Line T(s, t - s); //入射光线
int in_id = -1;
Point in_P; //入射点
for(int i = 0; i < 3; i++) {
double t;
if(isParallel(T, L[i])) continue; //直线平行,没有交点
Point p = GetLineIntersection(T, L[i], t);
if(dcmp(t) <= 0) continue;
if(!OnSegment(p, L[i].P, L[i].P + L[i].v)) continue; //交点不在线段上
if(in_id == -1 || Distance(s, p) < Distance(s, in_P)) {
in_P = p; in_id = i;
}
}
if(in_id == -1) { //没有射到棱镜上
double t;
if(dcmp(T.v.y) >= 0) printf("Error\n");
else printf("%.3f\n", GetLineIntersection(T, flat, t).x);
continue;
}
//printf("in_Point:");
//in_P.print();
Vector normal = Normal(L[in_id].v); //计算第一次折射的法线
if(dcmp(Dot(normal, T.v)) < 0) normal.x = -normal.x, normal.y = -normal.y; //调整法线的方向
double theta = asin(fabs(Cross(T.v, normal)) / Length(T.v) / Length(normal) / u);//计算折射角
Line T2; T2.P = in_P; //折射光线
if(dcmp(Cross(normal, T.v)) > 0) T2.v = Rotate(normal, theta);
else T2.v = Rotate(normal, -theta);
int out_id;
Point out_P; //出射点
for(int i = 0; i < 3; i++) if(i != in_id) {
if(isParallel(T2, L[i])) continue;
double t;
Point p = GetLineIntersection(T2, L[i], t);
if(dcmp(t) <= 0) continue;
if(!OnSegment(p, L[i].P, L[i].P + L[i].v)) continue;
out_P = p;
out_id = i;
}
//printf("out_Point:");
//out_P.print();
Vector normal2 = Normal(L[out_id].v);
if(dcmp(Dot(T2.v, normal2)) < 0) normal2.x = -normal2.x, normal2.y = -normal2.y;
double theta2 = asin(fabs(Cross(T2.v, normal2)) / Length(T2.v) / Length(normal2) * u);
Line T3; T3.P = out_P;
if(dcmp(Cross(normal2, T2.v)) > 0) T3.v = Rotate(normal2, theta2);
else T3.v = Rotate(normal2, -theta2);
double t;
if(dcmp(T3.v.y) >= 0) printf("Error\n");
else printf("%.3f\n", GetLineIntersection(T3, flat, t).x);
}
return 0;
}
LA 5007 Detector Placement 模拟的更多相关文章
- hdu3712 Detector Placement
题意:给一束激光,一个三棱柱,三棱柱会折射光,问这束激光最终是否会和y = 0相交: 分析:模拟题,为了方便处理折射角,事先求出每条边的向内和向外的法向量: findpoint : 找第一交点 ste ...
- La Vie en rose (模拟)
#include<bits/stdc++.h> using namespace std; ; ; int T, n, m; char str1[maxm], str2[maxn]; int ...
- LA 3486 Cells(判祖先+栈模拟dfs)
https://vjudge.net/problem/UVALive-3486 题意: 判断u是否是v的祖先. 思路: 很简单,dfs遍历,记录每个节点第一次访问时的时间戳 in[i] 和第二次访问时 ...
- LA 4119 Always an integer (数论+模拟)
ACM-ICPC Live Archive 一道模拟题,题意是问一个给出的多项式代入正整数得到的值是否总是整数. 这题是一道数论题,其实对于这个式子,我们只要计算1~最高次项是否都满足即可. 做的时候 ...
- [ACM_模拟][ACM_数学] LA 2995 Image Is Everything [由6个视图计算立方体最大体积]
Description Your new company is building a robot that can hold small lightweight objects. The robo ...
- HDU 5745 La Vie en rose (DP||模拟) 2016杭电多校联合第二场
题目:传送门. 这是一道阅读理解题,正解是DP,实际上模拟就能做.pij+1 指的是 (pij)+1不是 pi(j+1),判断能否交换输出即可. #include <iostream> # ...
- LA 2995 立方体成像(模拟)
题目链接:https://vjudge.net/problem/UVALive-2995 这道题的主要难点在于三维坐标系的建立,然后在坐标系中进行迭代更新. 注意用宏定义来简化代码. AC代码: #i ...
- LA 3708 墓地雕塑(模拟)
题目链接:https://vjudge.net/problem/UVALive-3708 这道题的思路也是比较难想. 首先根据上一题(Uva 11300)可知,要想让移动距离最短,那么至少要使一个雕塑 ...
- Codeforces 738D. Sea Battle 模拟
D. Sea Battle time limit per test: 1 second memory limit per test :256 megabytes input: standard inp ...
随机推荐
- MyBatis学习总结(三)---映射文件及引入方式
MyBatis的强大,主要原于它强大映射功能,相对其它的jdbc,使用MyBatis,你会发现省掉很多代码.上一篇已经简单做出一个实例.今天就了解一下MyBatis的映射xml文件. 了解上一篇fri ...
- 集合、迭代器、增强for循环、泛型
1集合 集合是java中提供的一种容器,可以用来存储多个数据. 数组的长度是固定的.集合的长度是可变的.集合中存储的元素必须是引用类型数据. 1.1ArrayList集合存储元素(复习) 例: pub ...
- Vue Scroller:Vue 下拉刷新及无限加载组件
Vue Scroller Vue Scroller is a foundational component ofVonic UI. In purpose of smooth scrolling, pu ...
- javascript简单计算器实践
参考部分资料,编写一个简单的计算器案例,虽然完成了正常需求,但是也有不满之处,待后续实力提升后再来补充,先把不足之处列出: 1:本来打算只要打开页面,计算器的输入框会显示一个默认为0的状态,但是在输入 ...
- SharePoint运行状况分析器有关磁盘空间不足的警告
对于负责管理SharePoint内部部署安装的SharePoint管理员,SharePoint Health Analyzer是一款出色的工具.此功能不仅有助于解决服务器故障和服务失败的问题,还提供了 ...
- LINQ新添知识
linquser.ExecuteCommand("TRUNCATE TABLE Board"); linquser.ExecuteCommand("DELET ...
- JavaScript_9_循环
1. JavaScript for/in 语句循环遍历对象的属性: 可以遍历数组,也可以遍历一个对象的所有属性 <body> <p>点击按钮,循环遍历对象“person”的属性 ...
- HDU 1124 Factorial (阶乘后缀0)
题意: 给一个数n,返回其阶乘结果后缀有几个0. 思路: 首先将n个十进制数进行质因数分解,观察的得到只有2*5才会出现10.那么n!应含有min(2个数,5个数)个后缀0,明显5的个数必定比2少,所 ...
- LeetCode House Robber 家庭劫犯(dp)
题意:有一个整数序列,从中挑出一些数字,使得总和是最大,前提是,相邻的两个数字中只能挑其一.比如1 2 3 就只能挑2或者1和3. 思路:很直观的题,dp思想.降低规模,从小规模开始考虑.如果只有两个 ...
- BZOJ 4423: [AMPPZ2013]Bytehattan 并查集+平面图转对偶图
4423: [AMPPZ2013]Bytehattan Time Limit: 3 Sec Memory Limit: 128 MB Submit: 277 Solved: 183 [Submit ...