在关键时候 总是一次又一次的失误在精度上面 在轻工业的校赛中 失误在读数 整整浪费了将近3个小时
题意相对来说比较简单 就是问三维的点到三维的一条线段的最短距离
一共四种可能
点在线段上,距离为0;
线段是一个点,用两点公式求;
三点构成直角三角形或者钝角三角形,那么直角或者钝角即为点到线段最近的点;
三点构成锐角三角形,那么距离为三角形的高,点到线段最近的点。
线段是一个点,用两点公式求;
三点构成直角三角形或者钝角三角形,那么直角或者钝角即为点到线段最近的点;
三点构成锐角三角形,那么距离为三角形的高,点到线段最近的点。
方法一:利用向量来求取夹角 从而判断那一点的位置
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #include<map> #include<vector> #include<math.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define N 100009 struct node { double x,y,z; }a[N]; double q(node a,node b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z)); } int xiang(node a,node b) { return (a.x*b.x+a.y*b.y+a.z*b.z); } int main() { int T,m; double x1,x2,y1,y2,nn; scanf("%d",&T); while(T--) { scanf("%lf%lf%lf%lf%lf",&nn,&x1,&y1,&x2,&y2); if(x1>x2) { swap(x1,x2); swap(y1,y2); } a[0].x=x1;a[0].y=y1;a[0].z=nn; a[1].x=x2;a[1].y=y2;a[1].z=nn; scanf("%lf%lf%lf",&a[2].x,&a[2].y,&a[2].z); scanf("%lf%lf%lf",&a[4].x,&a[4].y,&a[4].z); scanf("%d",&m); for(int i=0;i<m;i++) { int n; scanf("%d",&n); a[5].x=a[2].x+n*a[4].x; a[5].y=a[2].y+n*a[4].y; a[5].z=a[2].z+n*a[4].z;///现在的三点为0 1 5 a[6].x=a[5].x-a[0].x;a[6].y=a[5].y-a[0].y;a[6].z=a[5].z-a[0].z;///向量0 5 a[7].x=a[5].x-a[1].x;a[7].y=a[5].y-a[1].y;a[7].z=a[5].z-a[1].z;///向量1 5 a[8].x=a[0].x-a[1].x;a[8].y=a[0].y-a[1].y;a[8].z=a[0].z-a[1].z;///向量1 0 a[9].x=-a[8].x;a[9].y=-a[8].y;a[9].z=-a[8].z;///向量0 1 double e=q(a[0],a[5]);///0 5两点的长度 double f=q(a[1],a[5]);///1 5两点的长度 double g=q(a[0],a[1]);///0 1两点的长度 double x=xiang(a[7],a[8]);///向量15与向量10的乘积 double y=xiang(a[6],a[9]);///向量05与向量01的乘积 double t; if(x<=0||y<=0)///乘积小于等于0即为在直角钝角三角形 直接找e与f最小值 t=min(e,f); else///点5 在0 1上方 { double cos1=1.0*x/(f*g); if(fabs(1-cos1)<1e-6)///避免在同一线段上 t=0; else t=f*sin(acos(cos1)); } printf("%.2f ",t); } } return 0; }
方法二:利用海伦公式 求高再使用勾股定理
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #include<map> #include<vector> #include<math.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define N 100009 struct node { double x,y,z; }a[N]; double q(node a,node b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z)); } int Q(node a,node b,node c) { return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y); } int main() { int T,m; double x1,x2,y1,y2,nn; scanf("%d",&T); while(T--) { scanf("%lf%lf%lf%lf%lf",&nn,&x1,&y1,&x2,&y2); if(x1>x2)///置换位置 让x1<x2 用于判断共线 { swap(x1,x2); swap(y1,y2); } a[0].x=x1;a[0].y=y1;a[0].z=nn; a[1].x=x2;a[1].y=y2;a[1].z=nn; scanf("%lf%lf%lf",&a[2].x,&a[2].y,&a[2].z); scanf("%lf%lf%lf",&a[4].x,&a[4].y,&a[4].z); scanf("%d",&m); for(int i=0;i<m;i++) { int n; scanf("%d",&n); a[5].x=a[2].x+n*a[4].x;///此刻的气球三维坐标 a[5].y=a[2].y+n*a[4].y; a[5].z=a[2].z+n*a[4].z; if(a[0].x==a[1].x&&a[0].y==a[1].y)///判断飞船两端点是否同点 { double gao=q(a[0],a[5]); printf("%.2f ",gao); continue; } if(Q(a[5],a[0],a[1])==0)///利用叉积 判断三点是否共线 { double b,c; if(a[5].x>=a[0].x&&a[5].x<=a[1].x) b=0; else { b=q(a[0],a[5]); c=q(a[1],a[5]); b=min(b,c); } printf("%.2f ",b); continue; } double b=q(a[0],a[5]);///总体思想 利用面积求出高的长度 判断高是否在三点组成的三角形里面 double c=q(a[1],a[5]); double d=q(a[0],a[1]); double ans=1.0*(b+c+d)/2;///利用海伦公式 求出来面积 double mianji=sqrt(1.0*ans*(ans-d)*(ans-b)*(ans-c)); double gao=mianji*2/d;///利用底边 求出高 double sum=max(b,c);///与另外两边找到最大边 double chang=sqrt(sum*sum-gao*gao);///勾股定理 if(chang>=d)///如果所求高与最长边的第三边大于底边 证明高在三角形外 b=min(b,c); else b=gao; printf("%.2f ",b); } } return 0; }