很郁闷的一题,第一次碰到使用不同的编译器,一个超时(C++),一个AC的情况(G++)。。。
首先题中的要求等价于:存在一条直线l和所有的线段都相交。
证明:若存在一条直线l和所有线段相交,作一条直线m和l垂直,则m就是题中要求的直线所有线段投影的一个公共点即为垂足。(l和每条线段的交点沿l投影到m上的垂足处)反过来,若存在m,所有线段在m上的投影有公共点,则过这点垂直于m作直线l, l一定和所有线段相交。
然后证存在l和所有线段相交等价于存在l过某两条线段的各一个端点且和所有线段相交。充分性显然。必要性:若有l和所有线段相交,则可保持l和所有线段相交,左右平移l到和某一线段交于端点停止(“移不动了”)。然后绕这个交点旋转。也是转到“转不动了”(和另一线段交于其一个端点)为止。这样就找到了一个新的l。
于是本题可归结为枚举两两线段的各一个端点,连一条直线,再判断剩下的线段是否都和这条直线有交点。
注意:数据中有所有线段都缩成一个点的情况。
1#include<cstdio>
2#include<cstring>
3#include<algorithm>
4#include<vector>
5#include<complex>
6#include<cmath>
7#include<iostream>
8using namespace std;
9
10typedef complex<double> point;
11
12const int maxn = 330;
13const double eps = 1e-8;
14const double pi = acos( -1.0 );
15const double inf = 1e20;
16struct line
17{
18 point a, b;
19 line( ){ }
20 line( point u, point v ) : a( u ), b( v ){ }
21};
22
23point p[maxn<<1];
24line l[maxn];
25
26double operator ^( point p1, point p2 ) { return imag( conj(p1) * p2 ); }
27double operator &( point p1, point p2 ) { return real( conj(p1) * p2 ); }
28int dblcmp( double x ) { return ( x < -eps ? -1 : x > eps ); }
29
30bool same( point p1, point p2 )
31{
32 if( dblcmp( real(p1)- real(p2) ) == 0 && dblcmp( imag(p1) - imag(p2) ) == 0 )
33 return true;
34 return false;
35}
36// 判断线段l1是否与直线l2相交
37bool segcross( line l1, line l2 )
38{
39 if( dblcmp( l1.a - l2.a ^ l2.b - l2.a ) *
40 dblcmp( l2.b - l2.a ^ l1.b - l2.a ) >= 0 )
41 return true;
42 return false;
43}
44
45bool check( point p1, point p2, int n )
46{
47 line l0 = line( p1, p2 );
48 for( int k = 0; k < n; k++ )
49 if( !segcross( l[k], l0 ) ) return false;
50 return true;
51}
52
53bool solve( int n )
54{
55 int len = n << 1;
56 int cnt = 0;
57 for( int i = 0; i < len; i++ )
58 {
59 for( int j = i + 1; j < len; j++ )
60 {
61 if( same( p[i], p[j] ) )
62 {
63 cnt++;
64 continue;
65 }
66 if( check( p[i], p[j], n ) )
67 return true;
68 }
69 }
70 if( cnt == len * ( len - 1 ) / 2 ) return true;
71 return false;
72}
73
74int main( )
75{
76 int t, n;
77 double x1, x2, y1, y2;
78 //freopen("1005.in","r",stdin);
79 //freopen("out.txt","w",stdout);
80 scanf("%d",&t);
81 while( t-- )
82 {
83 scanf("%d",&n);
84 int len = 0;
85 for( int i = 0; i < n; i++ )
86 {
87 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
88 p[len++] = point( x1, y1 );
89 p[len++] = point( x2, y2 );
90 l[i] = line( p[len-2], p[len-1] );
91 }
92 if( solve( n ) ) printf("Yes\n");
93 else printf("No\n");
94 }
95 return 0;
96}
97