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, ...
随机推荐
- E:\Postgresql\pgAdmin4_binaryPath
e Path to the directory containing the EDB Advanced Server utility programs (pg_dump, pg_restore etc ...
- 125、TensorFlow计算图的执行
# TensorFlow使用tf.Session类来表示客户端程序之间的链接 # 虽然一个在其他语言中相似的接口也是可以使用的,列如C++ runtime # 一个tf.Session对象提供了访问本 ...
- python tensorflow windows环境搭建体验
1. 需先安装python3.7,anaconda包管理器(类似java的maven),tensorflow,pycharm开发工具.文末附件下载地址. 2. 安装tensorflow,开始-Anac ...
- 快速理解 session/token/cookie 认证方式
目录 目录 cookie session token cookie Web Application 一般以 HTTP 协议作为传输协议, 但 HTTP 协议是无状态的. 也就是说 server-sid ...
- CentOS7.X安装FastDFS-5.10
安装准备 yum install \ vim \ git \ gcc \ gcc-c++ \ wget \ make \ libtool \ automake \ autoconf \ -y \ 安装 ...
- Cef 重写alert与confirm弹窗
在使用form内嵌cef浏览本地页面的时候,如果出现alert弹窗,会在标题栏显示页面所在目录.所以想起来重写alert的样式,通过MessageBox进行提示,或者自己写一个弹窗. 以下代码基于 3 ...
- Convolutional Neural Networks(2):Sparse Interactions, Receptive Field and Parameter Sharing
Sparse Interactions, Receptive Field and Parameter Sharing是整个CNN深度网络的核心部分,我们用本文来具体分析其原理. 首先我们考虑Feedf ...
- 4期Web安全基础
介绍了web安全的各种常见漏洞.视频卡顿,建议直接看网易出品的白帽子视频. 类似的教程还有,网易白帽子的教程:参考简书https://www.jianshu.com/p/1b372ca96b87 在看 ...
- thphp(tp5)项目网站从Apache换成nginx报500
thphp(tp5)项目网站从Apache换成nginx报500 百度了一下,查看资料是Nginx配置fastcgi.conf的问题,打开文件编辑既可,如下图:
- spring-第十八篇之spring AOP基于XML配置文件的管理方式
1.在XML配置文件中配置切面.切入点.增强处理.spring-1.5之前只能使用XML Schema方式配置切面.切入点.增强处理. spring配置文件中,所有的切面.切入点.增强处理都必须定义在 ...