首页 > 代码库 > [POJ 2653]Pick-up sticks
[POJ 2653]Pick-up sticks
Description
Input
Output
The picture to the right below illustrates the first case from input.
Sample Input
5
1 1 4 2
2 3 3 1
1 -2.0 8 4
1 4 8 2
3 3 6 -2.0
3
0 0 1 1
1 0 2 1
2 0 3 1
0
Sample Output
题目大意
n个棍子,一个一个扔,如果扔在了别的棍子上,也就是说和别的棍子相交了,那么和它相交的棍子就会消失,求最后剩下的棍子的编号。
题解
考察的是线段与线段的相交判断。
判断两线段是否相交:
我们分两步确定两条线段是否相交:
(1)快速排斥试验
设以线段 P1P2 为对角线的矩形为R, 设以线段 Q1Q2 为对角线的矩形为T,如果R和T不相交,显然两线段不会相交。
(2)跨立试验
如果两线段相交,则两线段必然相互跨立对方。若P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 )
和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2
- Q1 ) < 0。上式可改写成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。当 (
P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以
P1 一定在线段 Q1Q2上;同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段
Q1Q2上。所以判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 )
>= 0。同理判断Q1Q2跨立P1P2的依据是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >=
0。具体情况如下图所示:
按理来说O(n2)绝对过不了,数据很水啊...
1 #include<set> 2 #include<map> 3 #include<ctime> 4 #include<cmath> 5 #include<queue> 6 #include<stack> 7 #include<cstdio> 8 #include<string> 9 #include<vector> 10 #include<cstring> 11 #include<cstdlib> 12 #include<iostream> 13 #include<algorithm> 14 #define LL long long 15 #define RE register 16 #define IL inline 17 using namespace std; 18 const int N=100000; 19 20 IL double Min(const double &a,const double &b){return a<b ? a:b;} 21 IL double Max(const double &a,const double &b){return a>b ? a:b;} 22 23 struct Point 24 { 25 double x,y; 26 Point (){} 27 Point (double _x,double _y){x=_x;y=_y;} 28 Point operator - (const Point &b) 29 const{ 30 return Point(x-b.x,y-b.y); 31 } 32 double operator * (const Point &b) 33 const{ 34 return x*b.y-y*b.x; 35 } 36 }; 37 struct Segment 38 { 39 Point a,b; 40 Segment (){} 41 Segment (Point _a,Point _b){a=_a;b=_b;} 42 bool operator & (const Segment &B) 43 const{ 44 if (Min(a.x,b.x)>Max(B.a.x,B.b.x)||Min(B.a.x,B.b.x)>Max(a.x,b.x)) return 0; 45 if (Min(a.y,b.y)>Max(B.a.y,B.b.y)||Min(B.a.y,B.b.y)>Max(a.y,b.y)) return 0; 46 if (((B.a-b)*(a-b))*((B.b-b)*(a-b))<=0&&((a-B.b)*(B.a-B.b))*((b-B.b)*(B.a-B.b))<=0) return 1; 47 return 0; 48 } 49 }segment[N+5]; 50 51 int n; 52 53 int main() 54 { 55 while (~scanf("%d",&n)&&n) 56 { 57 for (RE int i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&segment[i].a.x,&segment[i].a.y,&segment[i].b.x,&segment[i].b.y); 58 printf("Top sticks:"); 59 for (RE int i=1;i<n;i++) 60 { 61 RE int j; 62 for (j=i+1;j<=n;j++) if (segment[i]&segment[j]) break; 63 if (j>n) printf(" %d,",i); 64 } 65 printf(" %d.\n",n); 66 } 67 return 0; 68 }
[POJ 2653]Pick-up sticks