2017 山东一轮集训 Day2 Shadow (三维凸包点在面上投影)
在三维坐标中,给定一个点光源,一个凸多面体,以及一个平面作为地面。
求该凸多面体在地面上阴影的面积。
这三个点共同确定了一个平面,这个平面就是地面。保证这三个点坐标互异且不共线。前三行每行三个实数,每行表示一个点。这三个点共同确定了一个平面,这个平面就是地面。保证这三个点坐标互异且不共线。
接下来一行三个实数,表示一个点。这个点就是点光源。
之后一个整数n,表示凸多面体顶点的数量。
之后n行,每行三个实数,表示凸多面体的一个顶点。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <utility> #ifdef DEBUG
const int MAXN = ;
#else
const int MAXN = ;
#endif const double eps = 1e-; using namespace std; struct Vector {
double x, y, z;
Vector(double _x = , double _y = , double _z = ): x(_x), y(_y), z(_z) {}
Vector operator+(const Vector &rhs) const {
return Vector(x + rhs.x, y + rhs.y, z + rhs.z);
}
Vector operator-(const Vector &rhs) const {
return Vector(x - rhs.x, y - rhs.y, z - rhs.z);
}
Vector operator*(double k) {
return Vector(x * k, y * k, z * k);
}
double len() {
return sqrt(x * x + y * y + z * z);
}
};
typedef Vector Point; inline double dot(const Vector &a, const Vector &b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
} inline Vector cross(const Vector &a, const Vector &b) {
return Vector(a.y * b.z - b.y * a.z, a.z * b.x - b.z * a.x, a.x * b.y - a.y * b.x);
} bool flag;
inline Vector readv() {
double x, y, z;
scanf("%lf%lf%lf", &x, &y, &z);
if (flag) swap(y, z);
return Vector(x, y, z);
} inline void printv(const Vector &a) {
printf("(%lf, %lf, %lf)\n", a.x, a.y, a.z);
} struct Line {
Point s;
Vector d;
Line() {}
Line(Point _s, Point _t): s(_s), d(_t - _s) {}
}; struct Plain {
Point s;
Vector d;
Plain() {}
Plain(Point a, Point b, Point c): s(a), d(cross(b - a, c - a)) {}
} p;
Point s;
int n;
Point pol[MAXN];
Point sd[MAXN]; inline int dcmp(double x) {
return x < -eps ? - : x > eps ? : ;
} inline Point itsct(Line l, Plain p) {
double s1 = dot(p.d, l.s - p.s);
double s2 = dot(p.d, l.s + l.d - p.s);
if (!dcmp(s1 - s2)) {
return itsct(Line(l.s, l.s + p.d), p);
}
double k = s1 / (s1 - s2);
return l.s + l.d * k;
} bool cmp(const Point &a, const Point &b) {
return a.x < b.x;
} Point conv[MAXN];
inline int make_convex() {
int cnt = ;
sort(sd, sd + n, cmp);
conv[cnt++] = sd[];
for (int i = ; i < n; i++) {
while (cnt > && dcmp(cross(sd[i] - conv[cnt - ], conv[cnt - ] - conv[cnt - ]).z) < ) cnt--;
if (dcmp((conv[cnt - ] - sd[i]).len())) conv[cnt++] = sd[i];
}
for (int i = n - ; i >= ; i--) {
while (cnt > && dcmp(cross(sd[i] - conv[cnt - ], conv[cnt - ] - conv[cnt - ]).z) < ) cnt--;
if (dcmp((conv[cnt - ] - sd[i]).len())) conv[cnt++] = sd[i];
}
return cnt;
} inline void open_file() {
freopen("shadow.in", "r", stdin);
freopen("shadow.out", "w", stdout);
} int main() {
//open_file();
Point a = readv(), b = readv(), c = readv();
if (!dcmp(cross(b - a, c - a).z)) {
swap(a.y, a.z), swap(b.y, b.z), swap(c.y, c.z);
flag = true;
}
p = Plain(a, b, c);
s = readv();
scanf("%d", &n);
for (int i = ; i < n; i++) pol[i] = readv();
for (int i = ; i < n; i++) sd[i] = itsct(Line(s, pol[i]), p);
int cnt = make_convex();
double ans = ;
for (int i = ; i < cnt - ; i++) {
ans += cross(conv[i] - conv[], conv[i + ] - conv[]).len();
}
printf("%.2lf\n", ans / ); return ;
}
直接给你平面方程
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath> using namespace std; typedef struct p1node
{
double a,b,c,d;
}plane;
plane Pl; typedef struct p2node
{
double x,y,z;
}point;
point temp;
point P[ ];
point S[ ]; //计算点在平面上的投影
int shadow( plane p, point s, int n )
{
//求出过s平行于plane的平面 ax+by+c=D
double D = p.a*s.x+p.b*s.y+p.c*s.z;
if ( D-p.d < ) {//调整方向
p.a *= -;p.b *= -;p.c *= -;
p.d *= -;
D *= -;
} //判断点与面的关系
int count = ;
for ( int i = ; i < n ; ++ i ) {
double det = p.a*P[i].x+p.b*P[i].y+p.c*P[i].z-D;
if ( det < ) count ++;
}
if ( count == ) return ;
if ( count != n ) return n+; for ( int i = ; i < n ; ++ i ) {
//直线方程: (Sx,Sy,Sz) + t(dx,dy,dz)
double dx = P[i].x - s.x;
double dy = P[i].y - s.y;
double dz = P[i].z - s.z;
double t = (p.d-p.a*s.x-p.b*s.y-p.c*s.z)/(p.a*dx+p.b*dy+p.c*dz); P[i].x = s.x + t*dx;
P[i].y = s.y + t*dy;
P[i].z = s.z + t*dz;
}
return n;
} //坐标系旋转,到x-y平面
void change( plane p, int n )
{
//平行于x-y平面的不用计算,也不能计算(分母为0)
if ( p.a*p.a + p.b*p.b == ) return;
for ( int i = ; i < n ; ++ i ) {
//绕z轴旋转
double cosC = p.b/sqrt(p.a*p.a+p.b*p.b);
double sinC = p.a/sqrt(p.a*p.a+p.b*p.b);
temp.x = P[i].x*cosC-P[i].y*sinC;
temp.y = P[i].x*sinC+P[i].y*cosC;
temp.z = P[i].z;
P[i] = temp;
//绕x轴旋转
double cosA = p.c/sqrt(p.a*p.a+p.b*p.b+p.c*p.c);
double sinA = sqrt(p.a*p.a+p.b*p.b)/sqrt(p.a*p.a+p.b*p.b+p.c*p.c);
temp.x = P[i].x;
temp.y = P[i].y*cosA-P[i].z*sinA;
temp.z = P[i].y*sinA+P[i].z*cosA;
P[i] = temp;
}
} //计算二维凸包面积
double crossproduct( point a, point b, point c )
{
return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
} bool cmp1( point a, point b )
{
if ( a.x == b.x )
return a.y < b.y;
return a.x < b.x;
} bool cmp2( point a, point b )
{
return crossproduct( P[], a, b )>;
} void Graham( int n )
{
sort( P+, P+n, cmp1 );
sort( P+, P+n, cmp2 ); int top = -;
if ( n > ) S[++ top] = P[];
if ( n > ) S[++ top] = P[];
if ( n > ) {
for ( int i = ; i < n ; ++ i ) {
while ( crossproduct( S[top-], S[top], P[i] ) < ) -- top;
S[++ top] = P[i];
}
} double area = 0.0;
for ( int i = ; i <= top ; ++ i )
area += crossproduct( S[], S[i-], S[i] ); printf("%.2lf\n",area*0.5);
} int main()
{
int n;
while ( cin >> Pl.a >> Pl.b >> Pl.c >> Pl.d ) {
if ( Pl.a == && Pl.b == && Pl.c == ) break;
cin >> n;
for ( int i = ; i <= n ; ++ i )
cin >> P[i].x >> P[i].y >> P[i].z; int s_count = shadow( Pl, P[n], n );
if ( !s_count )
cout << "0.00" << endl;
else if ( s_count > n )
cout << "Infi" << endl;
else {
change( Pl, s_count );
Graham( s_count );
}
}
}
2017 山东一轮集训 Day2 Shadow (三维凸包点在面上投影)的更多相关文章
- LOJ #6062. 「2017 山东一轮集训 Day2」Pair
这是Lowest JN dalao昨天上课讲的一道神题其实是水题啦 题意很简单,我们也很容易建模转化出一个奇怪的东西 首先我们对b进行sort,然后我们就可以通过二分来判断出这个数可以和哪些数配对 然 ...
- loj#6062. 「2017 山东一轮集训 Day2」Pair hall定理+线段树
题意:给出一个长度为 n的数列 a和一个长度为 m 的数列 b,求 a有多少个长度为 m的连续子数列能与 b匹配.两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当 ...
- 【LOJ6062】「2017 山东一轮集训 Day2」Pair(线段树套路题)
点此看题面 大致题意: 给出一个长度为\(n\)的数列\(a\)和一个长度为\(m\)的数列\(b\),求\(a\)有多少个长度为\(m\)的子串与\(b\)匹配.数列匹配指存在一种方案使两个数列中的 ...
- ACM-ICPC 2017 西安赛区现场赛 K. LOVER II && LibreOJ#6062. 「2017 山东一轮集训 Day2」Pair(线段树)
题目链接:西安:https://nanti.jisuanke.com/t/20759 (计蒜客的数据应该有误,题目和 LOJ 的大同小异,题解以 LOJ 为准) LOJ:https://l ...
- LOJ6062「2017 山东一轮集训 Day2」Pair(Hall定理,线段树)
题面 给出一个长度为 n n n 的数列 { a i } \{a_i\} {ai} 和一个长度为 m m m 的数列 { b i } \{b_i\} {bi},求 { a i } \{a_i\} ...
- 【LOJ6067】【2017 山东一轮集训 Day3】第三题 FFT
[LOJ6067][2017 山东一轮集训 Day3]第三题 FFT 题目大意 给你 \(n,b,c,d,e,a_0,a_1,\ldots,a_{n-1}\),定义 \[ \begin{align} ...
- Loj #6069. 「2017 山东一轮集训 Day4」塔
Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...
- Loj #6073.「2017 山东一轮集训 Day5」距离
Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ...
- Loj 6068. 「2017 山东一轮集训 Day4」棋盘
Loj 6068. 「2017 山东一轮集训 Day4」棋盘 题目描述 给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置 $ (x, y),(u, ...
随机推荐
- python 数字系列-无穷大与NaN
无穷大与NaN 问题 你想创建或测试正无穷.负无穷或NaN(非数字)的浮点数. 解决方案 Python并没有特殊的语法来表示这些特殊的浮点值,但是可以使用 float() 来创建它们.比如: > ...
- 非典型T_SQL的总结
------over的两种常用的用法--- --第一种分组 当然要注意了,这里的分组并不是实际的分组,而是根据你的业务需求而坐的临时分组 select roomguid,Room, avg(t ...
- MySQL 服务器性能剖析
这是<高性能 MySQL(第三版)>第三章的读书笔记. 关于服务,常见的问题有: 如何确认服务器是否发挥了最大性能 找出执行慢的语句,为何执行慢 为何在用户端发生间歇性的停顿.卡死 通过性 ...
- 【报错】An error happened during template parsing (template: "class path resource [templates/hello1.html]")
页面显示: Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing t ...
- 解读vue filter
1.全局filter, 全局的过滤一般在main.js里面使用 <div id="app"> <div> {{testVal | filVal(10,30) ...
- (Vue)移动端点击输入框,弹出键盘,底部被顶起问题
(Vue)移动端点击输入框,弹出键盘,底部被顶起问题:https://www.jianshu.com/p/210fbc846544 问题描述:Vue开发中,当我们相对于父视图的底部布局子控件时,需要用 ...
- [已解决]报错: Windows下Redis服务无法启动,错误 1067 进程意外终止解决方案
启动redis时出现的报错内容: 解决方法: 找到登录状态 如果是网络服务,直接双击此服务,修改为本地系统服务即可启动!
- SpringBoot实现上传下载(二)
这篇写下载. **1.实现思路** 上一篇的数据库设计中,我们有一个字段始终没有用到fileName,这是用来给Layer对象存储文件名的,以此来完成文件与对象的对应, { //指数为0 if( ...
- 《剑指offer》面试题8 旋转数组的最小数字 Java版
(找递增排序旋转数组中的最小数字) 书中方法:这种题目就是要寻找数组的特点,然后根据这个特点去写.旋转后的递增数组分为两段递增序列,我们找到中点,如果比第一个元素大,表示在第一段递增序列里,如果比第一 ...