HDU 3471 England vs Germany 【三维线段判定】

HDU 3471 England vs Germany 【三维线段判定】

2010MU(ACM2010多校联合训练)-Fourth-UESTC-C Problem-England vs Germany-Solution Report

前言:这个2B题。谁出的谁自杀去。题目描述和数据还有官方解题报告都对着干。我们这帮做题的情何以堪!?

Description

 

The big fight between England and Germany was destroyed by the guy called Larrionda. England could have made a tie of 2:2. But that poor guy disqualified Lampard's wonderful goal. The ball passed through the goal line by half a meter, however, Larrionda turned a blind eye to this goal.

As a fan of Three Lion Regimen, silentsky want to develop a system which uses sensors to get the information to check if it scored or not.

 

The information includes a point as the location of ball, a vector as the velocity and a cuboid as the goal.

译文大意:

三狮军团和德意志战车单挑的时候,裁判拉里昂达2B了。因为拉里昂达的2B,那个完美进球被吹没了,本来有可能打平的比赛变成了日耳曼人屠戮了盎格鲁撒克逊人。

出题的人是个英粉,现在,他想让你编程构建一个系统来确定那个球到底是进还是没进。

所给信息包括,足球起始位置,速度矢量,以及,球门长方体八点。(均为三维坐标)

 

Input

The first line gives an integer t (t<=10000) indicating the number of test cases.

For each case:

The first line gives three real numbers x, y , z, indicating a point to represent the ball.

The second line gives three real numbers a, b, c. indicates a vector to represent the velocity.

The following 8 lines give 8 points according the sequence A, B, C, D, E, F, G, H as is shown in the figure.

 Absolute value of all real numbers are smaller than 10000.

 It is guaranteed that the initial location of the ball is not inside the goal.

 译文:

第一行为测试数据组数(小于等于10000的整数)。

第二行是球的坐标。

第三行是速度矢量。

第4~11行是按序给出的A~H八点的坐标。

(以上数据除组数外均为实数)

所有实数的绝对值均小于10000。

确保球的初始位置不在球门 (这句话是让无数人WA的关键。实际的测试数据中给出了在球门内的数据。)(怎么说呢。是写解题报告和出题的人没有和写标程测试数据的人统一好意见呢。还是根本就没认真对待出题这种神圣的事情,纯粹2B了呢?!)
HDU 3471 England vs Germany 【三维线段判定】_第1张图片
(自己建的图,特意下载了个AutoCAD2010.花了一个小时玩明白一点点建了个图)

Output

 if it scored then output “Case X: Stupid Larrionda!!!”.otherwise output “Case X: Intelligent Larrionda!!!”.(X is the case number starting from 1).

 We consider ABCD as the front of the goal and AB,BC,CD,DA as the goalposts. A shoot scores if and only if it passes through the front of the goal and doesn't crash on the goalpost)

译文:如果球进了,我们就输出“Case X: Stupid Larrionda!!!”(第X种情况:愚蠢的拉里昂达!!!)否则就输出 “Case X: Intelligent Larrionda!!!”(第X种情况:聪明的拉里昂达!!!)(X从1开始计数)

(我们认为ABCD为球门,AB、BC、CD、DA为球门框,球进了的意思是,球从球门穿过并且未触碰到球门框。)

(可是扯淡的地方在于,门线竟然被当做了球门,我们很无奈,但是要尊重题意(去你妈的题意),没办法,还是把门线当做了门框。

这道题的关键就在于判断球是否从球门进入,而非从侧面或者背面或者上下面进入。)

(但是因为,球在球门内向球门里射这种情况的存在,使这道经典计算几何练习题变成了ws的扯淡题。下面将提到。)

Sample Input

1

20 0 5

-10 5 0

10 0 10

10 10 10

10 10 0

10 0 0

0 0 10

0 10 10

0 10 0

0 0 0

(模拟图在上面) 

Sample Output

Case 1: Stupid Larrionda!!!


题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3471

#include  < iostream >
#include 
< cstring >
#include 
< cmath >
#include 
< cstdio >
#include 
< cctype >
#include 
< cstdlib >
#include 
< algorithm >
#include 
< vector >
#define  MAX 1<<30
using   namespace  std;
const   double  eps = 1e - 8 ;
typedef 
long   long  ll;
int  main()
{
    typedef 
struct
    {
    
double  x;
    
double  y;
    
double  z;
    } plus; 
// 三维点坐标的结构。。话说有没有这样的STL啊?
    plus r[ 100 ],xa[ 100 ],p[ 100 ];

// 下面是我比赛的时候去恶补的高数知识。。下学期高数没学好啊。几何部分一窍不通。泪目。。。
    /*  面法向量(本题中简易做法是AEvector) 

   * 本题中因为给出的是严格长方体,所以ABCD面法向量就是AEvector

   * 下面的法向量求法就没用了,不过学会了更好,我这个数学2B
   * x0=(y2-y1)*(z3-z1)-(z2-z1)*(y3-y1),
   * y0=(z3-z1)*(x2-x1)-(x3-x1)*(z2-z1),
   * z0=(x2-x1)*(y3-y1)-(x3-x1)*(y2-y1)
   * x0*(x-x1)+y0(y-y1)+z0(z-z1)=0

   * 直线参数方程是本题中判断球所在位置的关键
   * 直线参数方程 (p为始点,f为末点,即交点)
   * xf=xp+mt
   * yf=yp+nt
   * zf=zp+qt

   * 以下为求参数方程中t的关键
   * 线面相交方程
   * x0*(xp+mt-x1)+y0*(yp+nt-y1)+z0*(zp+qt-z1)=0
   * (x0*m+y0*n+z0*q)t=(x1-xp)*x0+(y1-yp)*y0+(z1-zp)*z0
   * 参数解法(即,交点确定方法) 
*/
  
   
//   freopen("eg.in","r",stdin);
   
//   freopen("fuck3.out","w",stdout);
    int  t,i,j,k,ca = 0 ;
   
double  temp[ 6 ],pp[ 100 ]; // ,r[4],l;
   plus o,v,m,f;
   scanf(
" %d " , & t);
   
while (t -- )
   {
    scanf(
" %lf%lf%lf " , & o.x, & o.y, & o.z);
    scanf(
" %lf%lf%lf " , & v.x, & v.y, & v.z);
    printf(
" Case %d:  " , ++ ca);
    
for (i = 0 ;i < 8 ;i ++ )
     scanf(
" %lf%lf%lf " , & p[i].x, & p[i].y, & p[i].z);
    m.x
= p[ 4 ].x - p[ 0 ].x;
    m.y
= p[ 4 ].y - p[ 0 ].y;
    m.z
= p[ 4 ].z - p[ 0 ].z;  // AEvector

    
// 将AEvector与速度矢量进行点积,判断速度与法向量是否同向

    
// 从而判断球是否射向球门内
     if (m.x * v.x + m.y * v.y + m.z * v.z <= eps)
     {
      printf(
" Intelligent Larrionda!!!\n " );
      
continue ;
     }

    
// 求由球点与速度矢量确定的直线方程与ABCD及EFGH面的交点

    
// temp[0]为与ABCD的交点的参数t的值

    
// temp[1]为与EFGH的交点的参数t的值 
    temp[ 0 = ( (p[ 0 ].x - o.x) * m.x + (p[ 0 ].y - o.y) * m.y + (p[ 0 ].z - o.z) * m.z ) / (m.x * v.x + m.y * v.y + m.z * v.z);
    temp[
1 = ( (p[ 4 ].x - o.x) * m.x + (p[ 4 ].y - o.y) * m.y + (p[ 4 ].z - o.z) * m.z ) / (m.x * v.x + m.y * v.y + m.z * v.z);

    
/* 判断球是否在球网EFGH的后面

    * 本来我只判断了球是否在球门之后,毕竟题目里说了球初始点不可能在球门内

    * 可是我事后去翻看了标程以及标程数据生成器,果然有这样的数据存在

    * 所以一开始sunyuqi和linyiyong同学竟然能把这道题过了,我表示非常震惊

    * 他们这叫歪打正着呢?还是有先见之明?

    * 学长们,以及我,都被那组不符合题意的数据卡死了。10+的WA。光辉的一B啊!

    * 1W组数据中的100组。被那2B的标程搞死。NND。

    
*/
    
if (temp[ 0 ] <= eps && temp[ 1 ] <= eps)
     {
      printf(
" Intelligent Larrionda!!!\n " );
      
continue ;
     }

    
// 前面一路判断都为真的话,则求ABCD与射球轨迹的交点
    f.x  =  o.x  +  temp[ 0 ] * v.x;
    f.y 
=  o.y  +  temp[ 0 ] * v.y;
    f.z 
=  o.z  +  temp[ 0 ] * v.z;

    
/*

    * 现在判断交点是否在ABCD面内

    *(严格内部,而非在这个平面上,但不在所包围的区域内)

    * 想法是,求出FAvector,FBvector,FCvector,FDvector(交点在F)

    * 再顺时针对这四个矢量求叉积,叉积即该平面(ABCD)的一侧法向量

    * 再判断这四个法向量是否在同侧即可

    * 判断方法为这四个叉积所得向量进行顺时针点积。均为正,则同向。

    
*/
    
for (i = 0 ;i < 4 ;i ++ )
    {
     r[i].x 
=  p[i].x  -  f.x;
     r[i].y 
=  p[i].y  -  f.y;
     r[i].z 
=  p[i].z  -  f.z;
    }
    
for (i = 0 ;i < 3 ;i ++ )
    {
     xa[i].x
=  r[i + 1 ].z * r[i].y - r[i + 1 ].y * r[i].z;
     xa[i].y
=  r[i + 1 ].x * r[i].z - r[i + 1 ].z * r[i].x;
     xa[i].z
=  r[i + 1 ].y * r[i].x - r[i + 1 ].x * r[i].y;
    }
    xa[
3 ].x =- ( r[ 3 ].z * r[ 0 ].y - r[ 3 ].y * r[ 0 ].z);
    xa[
3 ].y =- ( r[ 3 ].x * r[ 0 ].z - r[ 3 ].z * r[ 0 ].x);
    xa[
3 ].z =- ( r[ 3 ].y * r[ 0 ].x - r[ 3 ].x * r[ 0 ].y);
    
for (i = 0 ;i < 3 ;i ++ )
     {
      
if (xa[i].x * xa[i + 1 ].x + xa[i].y * xa[i + 1 ].y + xa[i].z * xa[i + 1 ].z > 0 );
      
else
       {printf(
" Intelligent Larrionda!!!\n " ); break ;}
     }
     
if (i == 3 )
      printf(
" Stupid Larrionda!!!\n " );
   }
   
//   system("pause");
   
//    fclose(stdin);
   
//   fclose(stdout);
    return   0 ;
}
/*  本题,我中间错了无数次。

 * 算法一改再改,从一开始判断球与球门的相对位置时计算点面距离,到中间的通过叉积矢量xyz坐标单纯相加判断是否同向,本人对高数以及计算几何进行了各种各样的练习。

 * 这还不算上,对于测试文件输入输出的学习,对于标程与自己程序对拍方法的学习。

 * 这道题消耗了我一天的时间,但是我觉得值,因为我深入理解了这个问题。虽然不代表我以后遇到这类问题能照AC不误,但至少,我从中收获了不少东西。

 * 顺便鄙视一下某些出题人。

 * 另外,本人的队友sunyuqi同学,做这题时运用了三维矩阵坐标变换的方法,鉴于本人线性代数超烂,故没学会,也就不摆上来献丑了。等以后学会了再来研究一下不迟。

 * 第一次写解题报告,如有错误,烦请指正。

 * 感谢各位百忙之中浏览本文。

 

 
*/

你可能感兴趣的:(HDU 3471 England vs Germany 【三维线段判定】)