uvalive 4795 Paperweight
题意:给出一个5个顶点的多面体以及多面体内一点P。求让 多面体不同的方式(即以不同的面)放在地面上,设这个着地的面为A,多面体重心在A上的投影为B,在保证B在A内部且距离A的各个边界不小于0.2的前提 下(否则这种放置方式就是不合法的),求P距离地面的最大最小距离为多少。
思路:
(1)判断两个点是不是在面的同一侧;否则这个面就不能作为着地的面;
(2)计算重心;
(3)计算点在面的投影;
(4)计算点是否在面内;
(5)计算点到线的距离;
(6)计算点到面的距离。
特殊情况:四点共面当底面.
#include<cstdio>
#include<cmath>
using namespace std; const double eps = 1e-;
int dcmp(double x)
{
if(fabs(x) < eps) return ;
else return x < ? - : ;
} struct Point3
{
double x, y, z;
Point3(double x=, double y=, double z=):x(x),y(y),z(z) { }
}; typedef Point3 Vector3; Vector3 operator + (const Vector3& A, const Vector3& B)
{
return Vector3(A.x+B.x, A.y+B.y, A.z+B.z);
} Vector3 operator - (const Point3& A, const Point3& B)
{
return Vector3(A.x-B.x, A.y-B.y, A.z-B.z);
} Vector3 operator * (const Vector3& A, double p)
{
return Vector3(A.x*p, A.y*p, A.z*p);
} Vector3 operator / (const Vector3& A, double p)
{
return Vector3(A.x/p, A.y/p, A.z/p);
} double Dot(const Vector3& A, const Vector3& B)
{
return A.x*B.x + A.y*B.y + A.z*B.z;
}
double Length(const Vector3& A)
{
return sqrt(Dot(A, A));
}
double Angle(const Vector3& A, const Vector3& B)
{
return acos(Dot(A, B) / Length(A) / Length(B));
}
Vector3 Cross(const Vector3& A, const Vector3& B)
{
return Vector3(A.y*B.z - A.z*B.y, A.z*B.x - A.x*B.z, A.x*B.y - A.y*B.x);
}
double Area2(const Point3& A, const Point3& B, const Point3& C)
{
return Length(Cross(B-A, C-A));
}
double Volume6(const Point3& A, const Point3& B, const Point3& C, const Point3& D)
{
return Dot(D-A, Cross(B-A, C-A));
} bool read_point3(Point3& p)
{
if(scanf("%lf%lf%lf", &p.x, &p.y, &p.z) != ) return false;
return true;
} // 点p到平面p0-n的距离。n必须为单位向量
double DistanceToPlane(const Point3& p, const Point3& p0, const Vector3& n)
{
return fabs(Dot(p-p0, n)); // 如果不取绝对值,得到的是有向距离
} // 点p在平面p0-n上的投影。n必须为单位向量
Point3 GetPlaneProjection(const Point3& p, const Point3& p0, const Vector3& n)
{
return p-n*Dot(p-p0, n);
} // 点P到直线AB的距离
double DistanceToLine(const Point3& P, const Point3& A, const Point3& B)
{
Vector3 v1 = B - A, v2 = P - A;
return Length(Cross(v1, v2)) / Length(v1);
} // p1和p2是否在线段a-b的同侧
bool SameSide(const Point3& p1, const Point3& p2, const Point3& a, const Point3& b)
{
return dcmp(Dot(Cross(b-a, p1-a), Cross(b-a, p2-a))) >= ;
} // 点在三角形P0, P1, P2中
bool PointInTri(const Point3& P, const Point3& P0, const Point3& P1, const Point3& P2)
{
return SameSide(P, P0, P1, P2) && SameSide(P, P1, P0, P2) && SameSide(P, P2, P0, P1);
} // 四面体的重心
Point3 Centroid(const Point3& A, const Point3& B, const Point3& C, const Point3& D)
{
return (A + B + C + D)/4.0;
} #include<algorithm>
//using namespace std; // 判断P是否在三角形A, B, C中,并且到三条边的距离都至少为mindist。保证P, A, B, C共面
bool InsideWithMinDistance(const Point3& P, const Point3& A, const Point3& B, const Point3& C, double mindist)
{
if(!PointInTri(P, A, B, C)) return false;
if(DistanceToLine(P, A, B) < mindist) return false;
if(DistanceToLine(P, B, C) < mindist) return false;
if(DistanceToLine(P, C, A) < mindist) return false;
return true;
} // 判断P是否在凸四边形ABCD(顺时针或逆时针)中,并且到四条边的距离都至少为mindist。保证P, A, B, C, D共面
bool InsideWithMinDistance(const Point3& P, const Point3& A, const Point3& B, const Point3& C, const Point3& D, double mindist)
{
if(!PointInTri(P, A, B, C)) return false;
if(!PointInTri(P, C, D, A)) return false;
if(DistanceToLine(P, A, B) < mindist) return false;
if(DistanceToLine(P, B, C) < mindist) return false;
if(DistanceToLine(P, C, D) < mindist) return false;
if(DistanceToLine(P, D, A) < mindist) return false;
return true;
} int main()
{
for(int kase = ; ; kase++)
{
Point3 P[], F;
for(int i = ; i < ; i++)
if(!read_point3(P[i])) return ;
read_point3(F); // 求重心坐标
Point3 c1 = Centroid(P[], P[], P[], P[]);
Point3 c2 = Centroid(P[], P[], P[], P[]);
double vol1 = fabs(Volume6(P[], P[], P[], P[])) / 6.0;
double vol2 = fabs(Volume6(P[], P[], P[], P[])) / 6.0;
Point3 centroid = (c1 * vol1 + c2 * vol2) / (vol1 + vol2); // 枚举放置方案
double mindist = 1e9, maxdist = -1e9;
for(int i = ; i < ; i++)
for(int j = i+; j < ; j++)
for(int k = j+; k < ; k++)
{
// 找出另外两个点的下标a和b
int vis[] = {};
vis[i] = vis[j] = vis[k] = ;
int a, b;
for(a = ; a < ; a++) if(!vis[a])
{
b = -i-j-k-a;
break;
} // 判断a和b是否在平面i-j-k的异侧(体积法判断)
int d1 = dcmp(Volume6(P[i], P[j], P[k], P[a]));
int d2 = dcmp(Volume6(P[i], P[j], P[k], P[b]));
if(d1 * d2 < ) continue; // 是,则放置方案不合法 Vector3 n = Cross(P[j]-P[i], P[k]-P[i]); // 法向量
n = n / Length(n); // 单位化 Point3 proj = GetPlaneProjection(centroid, P[i], n); // 重心在平面i-j-k上的投影
bool ok = InsideWithMinDistance(proj, P[i], P[j], P[k], 0.2);
if(!ok)
{
if(d1 == ) // i-j-k-a四点共面。i和j一定为ABC三个顶点之一,k和a是D或者E
{
if(!InsideWithMinDistance(proj, P[i], P[k], P[j], P[a], 0.2)) continue;
}
else if(d2 == ) // i-j-k-b四点共面。i和j一定为ABC三个顶点之一,k和b是D或者E
{
if(!InsideWithMinDistance(proj, P[i], P[k], P[j], P[b], 0.2)) continue;
}
else
continue;
} // 更新答案
double dist = DistanceToPlane(F, P[i], n);
mindist = min(mindist, dist);
maxdist = max(maxdist, dist);
}
printf("Case %d: %.5lf %.5lf\n", kase, mindist, maxdist);
}
return ;
}
uvalive 4795 Paperweight的更多相关文章
- UVALive - 4108 SKYLINE[线段树]
UVALive - 4108 SKYLINE Time Limit: 3000MS 64bit IO Format: %lld & %llu Submit Status uDebug ...
- UVALive - 3942 Remember the Word[树状数组]
UVALive - 3942 Remember the Word A potentiometer, or potmeter for short, is an electronic device wit ...
- UVALive - 3942 Remember the Word[Trie DP]
UVALive - 3942 Remember the Word Neal is very curious about combinatorial problems, and now here com ...
- 思维 UVALive 3708 Graveyard
题目传送门 /* 题意:本来有n个雕塑,等间距的分布在圆周上,现在多了m个雕塑,问一共要移动多少距离: 思维题:认为一个雕塑不动,视为坐标0,其他点向最近的点移动,四舍五入判断,比例最后乘会10000 ...
- UVALive 6145 Version Controlled IDE(可持久化treap、rope)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...
- UVALive 6508 Permutation Graphs
Permutation Graphs Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Submit ...
- UVALive 6500 Boxes
Boxes Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Submit Status Pract ...
- UVALive 6948 Jokewithpermutation dfs
题目链接:UVALive 6948 Jokewithpermutation 题意:给一串数字序列,没有空格,拆成从1到N的连续数列. dfs. 可以计算出N的值,也可以直接检验当前数组是否合法. # ...
- 【暑假】[实用数据结构]UVAlive 3135 Argus
UVAlive 3135 Argus Argus Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %l ...
随机推荐
- PAT-乙级-1012. 数字分类 (20)
1012. 数字分类 (20) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 给定一系列正整数,请按要求对数字进 ...
- 使用 Spark 进行微服务的实时性能分析
[编者按]当开发者从微服务架构获得敏捷时,观测整个系统的运行情况成为最大的痛点.在本文,IBM Research 展示了如何用 Spark 对微服务性能进行分析和统计,由 OneAPM 工程师编译整理 ...
- C++开发必看 四种强制类型转换的总结
C风格的强制类型转换(Type Cast)很简单,不管什么类型的转换统统是: TYPE b = (TYPE)a C++风格的类型转换提供了4种类型转换操作符来应对不同场合的应用. const_cast ...
- ***总结:在linux下连接redis并进行命令行操作(设置redis密码)
[root@iZ254lfyd6nZ ~]# cd / [root@iZ254lfyd6nZ /]# ls bin boot dev etc home lib lib64 lost+found med ...
- android dialog点击其他区域消失
只需调用dialog对象的setCanceledOnTouchOutside方法,传入参数为true即可. 如下代码实现: //点击其他区域dialog消失 menuDialog.setCancele ...
- linux MySQL安装配置
执行下面的命令初始化授权表: ./scripts/mysql_install_db --user=mysql
- tomcat context 配置 项目部署
将tomcat/conf/server.xml文件打开, 在</Host>标签之前添加: <Context path = "" docBase = "F ...
- gdb调试多线程程序总结
阿里核心系统团队博客 http://csrd.aliapp.com/?tag=pstack Linux下多线程查看工具(pstree.ps.pstack) http://www.cnblogs.com ...
- MVC @Html.DropDownListFor 默认值
今天在做MVC 的 @Html.DropDownListFor 的时候,本来数据库中读取到的值是HK,但是 @Html.DropDownListFor的起始默认值始终是“请选择国家”,搞了一个下午, ...
- log4cxx在linux下的编译和使用
[下载] [编译动态库] [使用动态库]