结合得好巧妙。。。。
化简后的问题是:
给你两个点集A,B,求B的一个子集BB,使得BB的凸包包含A的凸包,求BB的最小大小。
先特判答案为1,2的情况,答案为3的情况,我们先构造一个有向图:
对于B集合中的两个点u,v,如果 所有A集合的点都在u->v的左侧,那么就连一条u->v的边。
于是我们可以证明一个包含A的凸包和我们连出来的有向图中的环一一对应(不考虑点数小于等于2的情况)。
于是现在我们的问题就是求最小的一个环,用floyd搞,最后统计min(f[i][i])。
1 /************************************************************** 2 Problem: 1027 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:1308 ms 7 Memory:2008 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cmath> 12 #include <cstring> 13 #include <algorithm> 14 #define line(a,b) ((b)-(a)) 15 #define eps 1e-8 16 #define oo 0x3f3f3f3f 17 #define N 550 18 using namespace std; 19 20 int sg( double x ) { return (x>-eps)-(x<eps); } 21 struct Vector { 22 double x, y; 23 Vector(){} 24 Vector( double x, double y ):x(x),y(y){} 25 Vector operator-( const Vector &b ) const { return Vector(x-b.x,y-b.y); } 26 double operator^( const Vector &b ) const { return x*b.y-y*b.x; } 27 double operator&( const Vector &b ) const { return x*b.x+y*b.y; } 28 double len() { return sqrt(x*x+y*y); } 29 bool operator<( const Vector &b ) const { 30 return sg(x-b.x)<0 || (sg(x-b.x)==0 && sg(y-b.y)<0); 31 } 32 bool operator==( const Vector &b ) const { 33 return sg(x-b.x)==0 && sg(y-b.y)==0; 34 } 35 }; 36 typedef Vector Point; 37 38 int n, m; 39 Point aa[N], bb[N]; 40 int dis[N][N]; 41 42 bool onleft( const Point &a, const Point &b, const Point &c ) { 43 return sg(line(a,b)^line(a,c))>=0; 44 } 45 bool onseg( const Point &a, const Point &b, const Point &c ) { 46 return sg(line(a,b)^line(a,c))==0 && sg(line(c,a)&line(c,b))<0; 47 } 48 bool case1() { 49 if( m==1 ) { 50 for( int i=1; i<=n; i++ ) 51 if( aa[i]==bb[1] ) 52 return true; 53 } 54 return false; 55 } 56 bool case2() { 57 bool ok = true; 58 for( int i=1; i<=m && ok; i++ ) 59 for( int j=i+1; j<=m && ok; j++ ) 60 for( int k=j+1; k<=m && ok; k++ ) 61 if( sg((bb[i]-bb[j])^(bb[k]-bb[j])) ) 62 ok =false; 63 if( ok ) { 64 int ii=1, jj=1; 65 double ll = -1.0; 66 for( int i=1; i<=m; i++ ) 67 for( int j=i+1; j<=m; j++ ) { 68 double l = (bb[i]-bb[j]).len(); 69 if( l>ll ) { 70 ii = i; 71 jj = j; 72 ll = l; 73 } 74 } 75 for( int i=1; i<=n; i++ ) 76 for( int j=i+1; j<=n; j++ ) 77 if( onseg(aa[i],aa[j],bb[ii]) && onseg(aa[i],aa[j],bb[jj]) ) 78 return true; 79 } 80 return false; 81 } 82 int main() { 83 scanf( "%d%d", &n, &m ); 84 for( int i=1; i<=n; i++ ) { 85 double x, y, z; 86 scanf( "%lf%lf%lf", &x, &y, &z ); 87 aa[i] = Point(x,y); 88 } 89 for( int i=1; i<=m; i++ ) { 90 double x, y, z; 91 scanf( "%lf%lf%lf", &x, &y, &z ); 92 bb[i] = Point(x,y); 93 } 94 sort( bb+1, bb+1+m ); 95 m = unique( bb+1, bb+1+m ) - bb - 1; 96 sort( aa+1, aa+1+n ); 97 n = unique( aa+1, aa+1+n ) - aa - 1; 98 if( case1() ) { 99 printf( "1\n" ); 100 return 0; 101 } else if( case2() ) { 102 printf( "2\n" ); 103 return 0; 104 } 105 memset( dis, 0x3f, sizeof(dis) ); 106 for( int u=1; u<=n; u++ ) 107 for( int v=1; v<=n; v++ ) { 108 if( u==v ) continue; 109 bool ok = true; 110 for( int k=1; k<=m; k++ ) 111 if( !onleft(aa[u],aa[v],bb[k]) ) { 112 ok = false; 113 break; 114 } 115 if( ok ) { 116 dis[u][v] = 1; 117 } 118 } 119 for( int k=1; k<=n; k++ ) 120 for( int i=1; i<=n; i++ ) 121 for( int j=1; j<=n; j++ ) 122 dis[i][j] = min( dis[i][j], dis[i][k]+dis[k][j] ); 123 int ans = oo; 124 for( int i=1; i<=n; i++ ) { 125 if( dis[i][i]==2 ) continue; 126 ans = min( ans, dis[i][i] ); 127 } 128 printf( "%d\n", ans==oo ? -1 : ans ); 129 }
时间: 2024-10-29 19:07:21