bzoj 1027 floyd求有向图最小环

 

结合得好巧妙。。。。

化简后的问题是:

给你两个点集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 }
View Code

 

posted @ 2015-05-27 20:16  idy002  阅读(288)  评论(0编辑  收藏  举报