ZOJ 1648 Circuit Board

Circuit Board

Time Limit: 2 Seconds       Memory Limit: 65536 KB

On the circuit board, there are lots of circuit paths. We know the basic constrain is that no two path cross each other, for otherwise the board will be burned.

Now given a circuit diagram, your task is to lookup if there are some crossed paths. If not find, print "ok!", otherwise "burned!" in one line.

A circuit path is defined as a line segment on a plane with two endpoints p1(x1,y1) and p2(x2,y2).

You may assume that no two paths will cross each other at any of their endpoints.


Input

The input consists of several test cases. For each case, the first line contains an integer n(<=2000), the number of paths, then followed by n lines each with four float numbers x1, y1, x2, y2.


Output

If there are two paths crossing each other, output "burned!" in one line; otherwise output "ok!" in one line.


Sample Input

1
0 0 1 1

2
0 0 1 1
0 1 1 0


Sample Output

ok!
burned!

第一次写题解   :

题目大意:  电路板上有N条电路,但是各条电路是不能相交的,根据给出的数据判断,如果有电路相交  输出burned!,否则输出ok!。

解题思路:有多组测试数据,每组输入一个n,表示有n条路,P1(x1,y1),P2(x2,y2)表示每条线路的起终点。那么该题就是判断给出的所有线段中是否会相交的情况出现。

(1)快速排斥试验

     设以线段 P1P2 为对角线的矩形为R, 设以线段 Q1Q2 为对角线的矩形为T,如果R和T不相交,显然两线段不会相交。(不知道怎么用)

(2)跨立试验

(PS:下面的公式中*代表点积,×代表叉积)

 如果两线段相交,则两线段必然相互跨立对方。

若P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 ) 和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,  

( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0

当 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以 P1 一定在线段 Q1Q2上;

同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段 Q1Q2上。

 如果是直线    直线可以无限延长,所以如果 L1 跨立了 L2,那么L2 必定跨立 L1, 那么 L1 与 L2 必然相交

  但是    线段就要判断 L1 跨立 L2 并且 L2 跨立 L1 才能说明 二者相交。

如上两幅图   当两线段不相交时  ( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) <  0   所以P1P2跨立Q1Q2。

上式可改写成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。    ps:因为    A×B = -B×A

但是  ( Q1 - P1 ) × ( P2 - P1 ) * ( Q2 - P1 ) × ( P2 - P1 ) > 0  因为此时矢量 (Q2-P1)和 (Q1-P1)  并不位于( P2 - P1 )两侧  所以叉积所表示的向量方向相同。(下面还有具体解释)

所以Q1Q2并不跨立P1P2。上式可改写成( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) < 0。  

所以判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >  0。

同理判断Q1Q2跨立P1P2的依据是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >  0。

所以要求线段P1P2与Q1Q2相交    就必须满足上面两式。

 模板  P1P2跨立Q1Q2   

( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >  0

即(Px1-Qx1,Py2-Qy2)x (Qx1-Qx2,Qy1-Qy2) *(Qx1-Qx2,Qy1-Qy2) x (Px2-Qx1,Py2-Qy2) > 0     

即((Px1-Qx1)*(Qy1-Qy2)-(Py2-Qy2)*(Qx1-Qx2))*((Qx1-Qx2)*(Py2-Qy2)-(Qy1-Qy2)*(Px2-Qx1)) > 0

所以问题解决

PS:

向量的点积:

                 给你两个向量A(ax,ay),B(bx,by).

                 向量A和B的点积公式:A*B=ax*bx+ay*by.

向量的叉积:

                给你两个向量A(ax,by) ,B(bx,by).

                向量的叉积公式:A×B=ax*by-ay*bx.

                具体看下面的行列式:

                               i        j      k

             A×B =        ax     ay     0  =  ax*by-ay*bx   = |A|*|B|*sin<A,B>    

                               bx     by    0                 注意:叉积的结果仍然是个向量,A×B = -B×A

叉积的几何意义:

右手定则:如上图所示,红色的向量表示V×U的结果。四指形成一个平面,大拇指与四指形成的平面垂直,四个指从V扫描到U大拇指的指向就是叉乘所得向量的方向。

许多资料都是copy的大神的.

题目链接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1648

 1 #include<stdio.h>
 2 int n;
 3 
 4 struct
 5 {
 6     float x1;
 7     float y1;
 8     float x2;
 9     float y2;
10 }line[2010];
11 
12 float fun(int i, int j) //判断跨立
13 {
14     float s;
15     return s=((line[i].x1-line[j].x2)*(line[j].y1-line[j].y2)-(line[i].y1-line[j].y2)*(line[j].x1-line[j].x2)) 
16             *((line[j].x1-line[j].x2)*(line[i].y2-line[j].y2)-(line[j].y1-line[j].y2)*(line[i].x2-line[j].x2));
17 }
18 int main()
19 {
20     int i,j;
21     while(scanf("%d",&n)!=EOF)
22     {
23         int flog=0;
24         for( i = 0; i < n; i++)
25         {   scanf("%f%f%f%f",&line[i].x1,&line[i].y1,&line[i].x2,&line[i].y2);  }
26         if( n == 1 ) printf("ok!\n");
27         else
28         {
29             for( i = 0; i < n-1; i++)
30             {
31                 for( j = i+1 ;j < n; j++)
32                 {
33                     if(fun(i,j)>0)   //如果line[i]跨立line[j]下面继续判断line[j]是否跨立line[i]
34                     {
35                         if(fun(j,i)>0) {flog=1;break;}  //如果二者均跨立,那么就不用进行下面的判断,直接跳出循环
36                     }
37                 }
38                 if(flog == 1)
39                     break;
40             }
41             if(flog == 1)
42                 printf("burned!\n");
43             else
44                 printf("ok!\n");
45         }
46     }
47     return 0;
48 }

 

 

转载于:https://www.cnblogs.com/ACSnail/p/3272236.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值