在三维坐标中,给定一个点光源,一个凸多面体,以及一个平面作为地面。

求该凸多面体在地面上阴影的面积。

这三个点共同确定了一个平面,这个平面就是地面。保证这三个点坐标互异且不共线。前三行每行三个实数,每行表示一个点。这三个点共同确定了一个平面,这个平面就是地面。保证这三个点坐标互异且不共线。
接下来一行三个实数,表示一个点。这个点就是点光源。
之后一个整数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 (三维凸包点在面上投影)的更多相关文章

  1. LOJ #6062. 「2017 山东一轮集训 Day2」Pair

    这是Lowest JN dalao昨天上课讲的一道神题其实是水题啦 题意很简单,我们也很容易建模转化出一个奇怪的东西 首先我们对b进行sort,然后我们就可以通过二分来判断出这个数可以和哪些数配对 然 ...

  2. loj#6062. 「2017 山东一轮集训 Day2」Pair hall定理+线段树

    题意:给出一个长度为 n的数列 a和一个长度为 m 的数列 b,求 a有多少个长度为 m的连续子数列能与 b匹配.两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当 ...

  3. 【LOJ6062】「2017 山东一轮集训 Day2」Pair(线段树套路题)

    点此看题面 大致题意: 给出一个长度为\(n\)的数列\(a\)和一个长度为\(m\)的数列\(b\),求\(a\)有多少个长度为\(m\)的子串与\(b\)匹配.数列匹配指存在一种方案使两个数列中的 ...

  4. ACM-ICPC 2017 西安赛区现场赛 K. LOVER II && LibreOJ#6062. 「2017 山东一轮集训 Day2」Pair(线段树)

    题目链接:西安:https://nanti.jisuanke.com/t/20759   (计蒜客的数据应该有误,题目和 LOJ 的大同小异,题解以 LOJ 为准)     LOJ:https://l ...

  5. 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\} ...

  6. 【LOJ6067】【2017 山东一轮集训 Day3】第三题 FFT

    [LOJ6067][2017 山东一轮集训 Day3]第三题 FFT 题目大意 给你 \(n,b,c,d,e,a_0,a_1,\ldots,a_{n-1}\),定义 \[ \begin{align} ...

  7. Loj #6069. 「2017 山东一轮集训 Day4」塔

    Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...

  8. Loj #6073.「2017 山东一轮集训 Day5」距离

    Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ...

  9. Loj 6068. 「2017 山东一轮集训 Day4」棋盘

    Loj 6068. 「2017 山东一轮集训 Day4」棋盘 题目描述 给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置 $ (x, y),(u, ...

随机推荐

  1. 清北学堂Day 6之STL

    电脑突然一炸,什么都没有保存,凉了.(又出现了笔记凉凉事件嘤嘤嘤) 行吧慢慢回忆 就算我们会手写,我们也要学STL.吸了O2的STL可是要上天的. 数据结构 pair 使用方式: pair<类型 ...

  2. selenium自动化测试之【数据驱动测试】

    数据驱动测试是自动化测试的主流设计模式之一,相同的测试脚本使用不同的测试数据来执行,测试数据和测试行为进行了完全的分离,这样的测试脚本设计模式称为数据驱动.实施数据驱动测试的步骤:1.编写测试脚本,脚 ...

  3. canvas绘制随机颜色的柱形图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. TensorFlow学习笔记3-从MNIST开始

    TensorFlow学习笔记3-从MNIST开始学习softmax 本笔记内容为"从MNIST学习softmax regression算法的实现". 注意:由于我学习机器学习及之前 ...

  5. 20190818 On Java8 第八章 复用

    第八章 复用 组合语法 初始化引用有四种方法: 当对象被定义时.这意味着它们总是在调用构造函数之前初始化. 在该类的构造函数中. 在实际使用对象之前.这通常称为延迟初始化.在对象创建开销大且不需要每次 ...

  6. CSS实现背景图片屏幕自适应

    在做登陆页面等的首页的时候,经常会遇到需要放一张背景大图的情况,并且需要图片按比例缩放,来适应不同屏幕的大小. html代码如下: <!DOCTYPE html> <html lan ...

  7. 用Emacs编写mybatis

    用Emacs编写mybatis */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} ...

  8. Java并发编程:进程的创建

    Java并发编程:进程的创建 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} J ...

  9. 11、numpy——字符串函数

    NumPy 字符串函数 以下函数用于对 dtype 为 numpy.string_ 或 numpy.unicode_ 的数组执行向量化字符串操作. 它们基于 Python 内置库中的标准字符串函数. ...

  10. C#设计模式:桥接模式(Bridge Pattern)

    一,桥接模式,直接上代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; u ...