hdu 4741 Save Labman No.004
来源:互联网 发布:cocos2d x js教程 编辑:程序博客网 时间:2024/05/27 03:26
题目大意:求空间两条直线的最短距离及最近的点坐标
解题思路:http://wenku.baidu.com/view/ea02ff8a6529647d2728520c.html
代码实现1:
#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <iostream>using namespace std;struct node{ double x; double y; double z;}p[10], P, Q;long double s, t;long double pf(long double a, long double b){ return (a - b) * (a - b);}long double dis(node a, node b){ return sqrt(pf(a.x, b.x) + pf(a.y, b.y) + pf(a.z, b.z));}void Cal(){ long double t1 = pf(p[2].x, p[1].x) + pf(p[2].y, p[1].y) + pf(p[2].z ,p[1].z); long double t2 = (p[2].x - p[1].x) * (p[4].x - p[3].x) + (p[2].y - p[1].y) * (p[4].y - p[3].y) + (p[2].z - p[1].z) * (p[4].z - p[3].z); long double t3 = (p[1].x - p[2].x) * (p[1].x - p[3].x) + (p[1].y - p[2].y) * (p[1].y - p[3].y) + (p[1].z - p[2].z) * (p[1].z - p[3].z); long double t4 = pf(p[4].x, p[3].x) + pf(p[4].y, p[3].y) + pf(p[4].z ,p[3].z); long double t5 = (p[1].x - p[3].x) * (p[4].x - p[3].x) + (p[1].y - p[3].y) * (p[4].y - p[3].y) + (p[1].z - p[3].z) * (p[4].z - p[3].z); t = (t1 * t5 + t2 * t3) / (t1 * t4 - t2 * t2); s = (t2 * t5 + t3 * t4) / (t1 * t4 - t2 * t2);}int main(){ int t0; scanf("%d", &t0); for(int i = 1; i <= t0; i++) { for(int j = 1; j <= 4; j++) { scanf("%lf%lf%lf", &p[j].x, &p[j].y, &p[j].z); } Cal(); P.x = p[1].x + s * (p[2].x - p[1].x); P.y = p[1].y + s * (p[2].y - p[1].y); P.z = p[1].z + s * (p[2].z - p[1].z); Q.x = p[3].x + t * (p[4].x - p[3].x); Q.y = p[3].y + t * (p[4].y - p[3].y); Q.z = p[3].z + t * (p[4].z - p[3].z); long double ans = dis(P, Q); printf("%.6lf\n", (double)ans); printf("%.6lf %.6lf %.6lf %.6lf %.6lf %.6lf\n",(double)P.x, (double)P.y, (double)P.z, (double)Q.x, (double)Q.y, (double)Q.z); } return 0;}
http://blog.sina.com.cn/s/blog_a401a1ea0101ij9z.html
容易理解的常规方法:
已知空间中两线段,如果它们无限变粗,判断是否相交。(主要讨论不在同一平面的情况)
线段AB
问题的关键是求出这两条任意直线之间的最短距离,以及在这个距离上的两线最接近点坐标,判断该点是否在线段AB和线段CD上。
首先将直线方程化为对称式,得到其方向向量n1=(a1,b1,c1),n2=(a2,b2,c2).
再将两向量叉乘得到其公垂向量N=(x,y,z),在两直线上分别选取点A,B(任意),得到向量AB,
求向量AB在向量N方向的投影即为两异面直线间的距离了(就是最短距离啦)。
最短距离的求法:d=|向量N*向量AB|/|向量N|(上面是两向量的数量积,下面是取模)。
设交点为C,D,带入公垂线N的对称式中,又因为C,D两点分别满足一开始的直线方程,所以得到关于C(或D)的两个连等方程,分别解出来就好了!
没有理解的简单方法:
三维向量的叉积公式:
向量a×向量b=| i j k| |a1 b1 c1| |a2 b2 c2|
这是一个三阶行列式
其值为 (b1c2-b2c1, c1a2-a1c2, a1b2-a2b1)
(i、j、k分别为空间中相互垂直的三条坐标轴的单位向量)。
代码实现2:#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>using namespace std;struct Point{ double x, y, z; Point(double x = 0, double y = 0, double z = 0):x(x), y(y), z(z){}};typedef Point Vector;Vector operator + (Vector a, Vector b){return Vector(a.x + b.x, a.y + b.y, a.z + b.z);};Vector operator - (Vector a, Vector b){return Vector(a.x - b.x, a.y - b.y, a.z - b.z);};Vector operator * (Vector a, double b){return Vector(a.x * b, a.y * b, a.z * b);};Vector operator / (Vector a, double b){return Vector(a.x / b, a.y / b, a.z / b);};Vector Cross(Vector a, Vector b){ return Vector(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 Dot(Vector a, Vector b){ return (a.x * b.x + a.y * b.y + a.z * b.z);}double Getlen(Vector a){ return sqrt(a.x*a.x + a.y*a.y + a.z*a.z);}int main(){ Point a1, b1, a2, b2; int n; scanf("%d", &n); for(int i = 0; i < n; i ++) { scanf("%lf %lf %lf", &a1.x, &a1.y, &a1.z); scanf("%lf %lf %lf", &b1.x, &b1.y, &b1.z); scanf("%lf %lf %lf", &a2.x, &a2.y, &a2.z); scanf("%lf %lf %lf", &b2.x, &b2.y, &b2.z); Vector n1 = (a1 - b1); Vector n2 = (a2 - b2); Vector n = Cross(n1, n2); Vector ab = (a1 - a2); double ans = Dot(n , ab) / Getlen(n); Point p1 = a1, p2 = a2; Vector d1 = (b1 - a1), d2 = (b2 - a2); double t1 = Dot( Cross(p2 - p1, d2), Cross(d1, d2)); double t2 = Dot( Cross(p2 - p1, d1) , Cross(d1, d2)); double fm = Getlen(Cross(d1, d2)); t1 = t1 / (fm * fm); t2 = t2 / (fm * fm); Point p, q; p = (a1 + (b1 - a1) * t1); q = (a2 + (b2 - a2) * t2); printf("%.6f\n", fabs(ans)); printf("%.6f %.6f %.6f ",p.x, p.y, p.z); printf("%.6f %.6f %.6f\n",q.x, q.y, q.z); } return 0;}
有一点我好想吐槽:为什么一定要用long double 才能过,,,,郁闷无极限啊
- hdu 4741 Save Labman No.004
- hdu 4741 Save Labman No.004
- hdu 4741 Save Labman No.004
- HDU 4741 Save Labman No.004
- HDU 4741 Save Labman No.004
- HDU 4741 Save Labman No.004
- [HDU 4741]Save Labman No.004[计算几何][精度]
- hdu 4741 Save Labman No.004(计算几何)
- hdu 4741——Save Labman No.004
- Save Labman No.004
- POJ 4741 Save Labman No.004
- HDU4741 Save Labman No.004
- hdu 4741 Save Labman No.004 [2013年杭州ACM网络赛]
- hdu 4741 Save Labman No.004(2013杭州网络赛)
- HDU 4741 Save Labman No.004 2013 ACM/ICPC 杭州网络赛
- hdu 4741 Save Labman No.004 (求异面直线距离及交点)
- hdu 4741 Save Labman No.004 异面直线最短距离及对应的点
- HDU 4741 Save Labman No.004 (异面直线距离&直线与平面的交点)
- JAVA抽象类和接口
- hdu4740
- hdu 1035 Robot Motion
- linux下解压命令大全
- 字符串操作 replace 自己改的
- hdu 4741 Save Labman No.004
- 安装gstreamer-0.10.29
- redhat linux 5.6下安装jdk和tomcat
- Linux下递归列出仅所有常规文件或文件夹路径的方法
- 如何在UIimageview里显示一张图片里的某一部分
- lua+VS环境搭建
- Android 使用存放在存assets文件夹下的SQLite数据库
- c++中的4种新增的强制转换符
- [C++基础]宏定义、内联函数、普通函数的区别