题意:

给出一束光线(射线),和一块三角形的棱镜 以及 棱镜的折射率,问光线能否射到X轴上,射到X轴上的坐标是多少。

分析:

其实直接模拟就好了,注意到题目中说不会发生全反射,所以如果射到棱镜中的话就一定能射出来。

一开始判断一下能否经过棱镜折射,不能的话直接算和X轴有没有交点或者交点的坐标。

  1. 然后就是根据入射光线T1求入射点P1,注意直线可能和三角形的两条边都有交点,但最近的那个才是入射点。

    找到入射点就求法线,算角度,利用折射公式算折射角,求出折射光线T2。
  2. 第二部分其实和上面的过程是一样的,求出射点,根据公式算出射角,最后求得出射光线。
  3. 出射光线和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 模拟的更多相关文章

  1. hdu3712 Detector Placement

    题意:给一束激光,一个三棱柱,三棱柱会折射光,问这束激光最终是否会和y = 0相交: 分析:模拟题,为了方便处理折射角,事先求出每条边的向内和向外的法向量: findpoint : 找第一交点 ste ...

  2. La Vie en rose (模拟)

    #include<bits/stdc++.h> using namespace std; ; ; int T, n, m; char str1[maxm], str2[maxn]; int ...

  3. LA 3486 Cells(判祖先+栈模拟dfs)

    https://vjudge.net/problem/UVALive-3486 题意: 判断u是否是v的祖先. 思路: 很简单,dfs遍历,记录每个节点第一次访问时的时间戳 in[i] 和第二次访问时 ...

  4. LA 4119 Always an integer (数论+模拟)

    ACM-ICPC Live Archive 一道模拟题,题意是问一个给出的多项式代入正整数得到的值是否总是整数. 这题是一道数论题,其实对于这个式子,我们只要计算1~最高次项是否都满足即可. 做的时候 ...

  5. [ACM_模拟][ACM_数学] LA 2995 Image Is Everything [由6个视图计算立方体最大体积]

    Description   Your new company is building a robot that can hold small lightweight objects. The robo ...

  6. HDU 5745 La Vie en rose (DP||模拟) 2016杭电多校联合第二场

    题目:传送门. 这是一道阅读理解题,正解是DP,实际上模拟就能做.pij+1 指的是 (pij)+1不是 pi(j+1),判断能否交换输出即可. #include <iostream> # ...

  7. LA 2995 立方体成像(模拟)

    题目链接:https://vjudge.net/problem/UVALive-2995 这道题的主要难点在于三维坐标系的建立,然后在坐标系中进行迭代更新. 注意用宏定义来简化代码. AC代码: #i ...

  8. LA 3708 墓地雕塑(模拟)

    题目链接:https://vjudge.net/problem/UVALive-3708 这道题的思路也是比较难想. 首先根据上一题(Uva 11300)可知,要想让移动距离最短,那么至少要使一个雕塑 ...

  9. Codeforces 738D. Sea Battle 模拟

    D. Sea Battle time limit per test: 1 second memory limit per test :256 megabytes input: standard inp ...

随机推荐

  1. oracle备份imp命令大全

    oracle中imp命令详细解释 Oracle的导入有用程序(Import utility)同意从数据库提取数据,而且将数据写入操作系统文件.imp使用的基本格式:imp[username[/pass ...

  2. Web可用性设计的247条指导方针

    首页可用性设计 首页元素要清晰的关注用户的关键任务(避免“增加功能倾向(featuritis)”) 如果网站比较大,那么首页应包含搜索输入框 首页要十分清楚的提供产品(内容)分类 在首页或首页内一次点 ...

  3. 使用CRA开发的基于React的UI组件发布到内网NPM上去

    前言:构建的ES组件使用CNPM发布内网上过程 1. 使用Create-React-APP开的组件 如果直接上传到NPM,你引用的时候会报: You may need an appropriate l ...

  4. 在Unity3d中解析Lua脚本的方法

    由于近期项目中提出了热更新的需求,因此本周末在Lua的陪伴下度过.对Lua与Unity3d的搭配使用,仅仅达到了一个初窥门径的程度,记录一二于此.水平有限,欢迎批评指正. 网络上关于Lua脚本和Uni ...

  5. Mysql order by 排序 varchar 类型数据

    Mysql order by 排序 varchar 类型数据 varchar 类型字段排序,  会將数字当成字符串来处理.  排序规则一般是从左到右一位位来比较. +0之后 就转化成INT 类型排序 ...

  6. git上传布置代码 git优势

    ftp 软件 可直接上传至服务器但不便于管理 Git上传 GitHub/码云/codinghub 登录服务器 ssh 协议登录 ssh 账户@ip地址 密码 mkdir 创建文件 workspace ...

  7. str中的join方法,fromkeys(),set集合,深浅拷贝(重点)

    一丶对之前的知识点进行补充 1.str中的join方法.把列表转换成字符串 # 将列表转换成字符串,每个元素之间用_拼接 s = "_".join(["天",& ...

  8. AngularJS中最重要的核心功能

    以下是AngularJS中最重要的核心功能: 数据绑定: 模型和视图组件之间的数据自动同步. 适用范围: 这些对象参考模型.它们充当控制器和视图之间的胶水. 控制器: 这些Javascript函数绑定 ...

  9. Google Chrome 浏览器的备用(离线)安装程序

    Google Chrome 浏览器的备用(离线)安装程序(适用于 Windows) 如果您在使用 http://www.google.com/chrome 上的标准安装程序下载 Chrome 浏览器时 ...

  10. ubuntu下安装ffmpeg扩展

    可通过PPA进行安装 sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next sudo apt-get update sudo apt-get ...