计算几何入门题#1(点,线基本关系,点积叉积的理解)

POJ 2318(叉积判左右)

题意:

给一个有很多隔栏的箱子以及一些玩具的坐标,求箱子每个区域内玩具个数。

思路:

其实就是二分+叉积判断。
通过二分隔栏线段,得到一个玩具所在区域。
玩具(x,y)所在区域的判断方式是与左边隔栏叉积小于0,右边大于0.
第一次真正意义上做计算几何的题,对叉积理解还不够充分,连WA好多发,啊。。

代码:

/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const double eps(1e-6) ;
const int maxn = 5050 ;

struct Point{
    int x , y ;
    Point( int x = 0 , int y = 0 ) : x(x) , y(y){} ;
} ;
typedef Point Vector ;
int det( Vector a , Vector b ){
    return a.x * b.y - a.y * b.x ;
}
int u[maxn] , l[maxn] ;
int cnt[maxn] ;
int main(){
  //freopen("input.txt","r",stdin);
    int n , m ;
    int x1 , y1 , x2 , y2 ;
    while( cin >> n >> m >> x1 >> y1 >> x2 >> y2 && n ){
        cls( cnt ) ; cls( u ) ; cls( l ) ;
        for( int i = 0 ; i < n ; i++ ){
            scanf( "%d%d" , u+i , l+i ) ;
        }
        u[n] = l[n] = x2 ;
        for( int i = 0 ; i < m ; i++ ){
            int X , Y ;
            scanf( "%d%d" , &X , &Y ) ;
            int pos ;
            int L = 0 , R = n ;
            while( L <= R ){
                int M = ( L + R ) >> 1 ;
                if( det( Vector( u[M] - X , y1 - Y ) , Vector( l[M] - X , y2 - Y ) ) < 0 ){
                    pos = M ;
                    R = M - 1 ;
                }
                else
                    L = M + 1 ;
            }
            cnt[pos] ++ ;
        }
        for( int i = 0 ; i <= n ; i++ ){
            printf( "%d: %d\n" , i , cnt[i] ) ;
        }
        puts("");
    }
    return 0;
}

POJ 2398(叉积判左右)

题意:

给一个有很多隔栏的箱子以及一些玩具的坐标,求箱子区域内玩具个数为t(t>0)的区域数。

思路:

上一题改改代码顺手A了它。。

代码:

/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const double eps(1e-6) ;
const int maxn = 5050 ;

struct Point{
    int x , y ;
    Point( int x = 0 , int y = 0 ) : x(x) , y(y){} ;
} ;
typedef Point Vector ;
int det( Vector a , Vector b ){
    return a.x * b.y - a.y * b.x ;
}
int u[maxn] , l[maxn] ;
int cnt[maxn] ;
map<int,int>ms;
int main(){
  //freopen("input.txt","r",stdin);
    int n , m ;
    int x1 , y1 , x2 , y2 ;
    while( cin >> n >> m >> x1 >> y1 >> x2 >> y2 && n ){
        ms.clear() ;
        cls( cnt ) ; cls( u ) ; cls( l ) ;
        for( int i = 0 ; i < n ; i++ ){
            scanf( "%d%d" , u+i , l+i ) ;
        }
        sort( u , u+n ) ;
        sort( l , l+n ) ;
        u[n] = l[n] = x2 ;
        for( int i = 0 ; i < m ; i++ ){
            int X , Y ;
            scanf( "%d%d" , &X , &Y ) ;
            int pos ;
            int L = 0 , R = n ;
            while( L <= R ){
                int M = ( L + R ) >> 1 ;
                if( det( Vector( u[M] - X , y1 - Y ) , Vector( l[M] - X , y2 - Y ) ) < 0 ){
                    pos = M ;
                    R = M - 1 ;
                }
                else
                    L = M + 1 ;
            }
            cnt[pos] ++ ;
        }
        for( int i = 0 ; i <= n ; i++ ){
            ms[cnt[i]] ++ ;
        }
        map<int,int>::iterator it = ms.begin() ;
        puts("Box");
        for( ; it != ms.end() ; it++ ){
            if( it->first > 0 )
                printf("%d: %d\n", it->first , it->second ) ;
        }
    }
    return 0;
}

POJ 3304 Segments (判断线段直线相交)

题意:

输入一些线段,问是否存在一条直线使所有线段在直线上的投影都有公共点。

思路:

若存在一条直线使所有线段在直线上的投影都有公共点,等价于存在一条直线与所有线段相交。

证明:
存在一条直线使所有线段在直线上的投影都有公共点,作这条直线的垂线,则垂线与所有线段相交。

枚举所有线段的两个端点连成直线,若这条直线经过所有线段,则存在一条直线与所有线段相交。

证明:若存在一条直线与所有线段相交,则可保持该直线与所有线段相交,将其平移至交于某一端点,再旋转该线段,使其交于第二个端点。

代码:

/*
 * @author FreeWifi_novicer
 * language : C++/C
 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;
const double eps(1e-10) ;
const int maxn = 100 + 5 ;

struct Point{
    double x , y ;
    Point( double x = 0 , double y = 0 ) : x(x) , y(y) {}
};

typedef Point Vector ; 

Vector operator - ( Point a , Point b ){
    return Vector( a.x - b.x , a.y - b.y ) ;
}
double det( Vector a , Vector b ){
    return a.x * b.y - a.y * b.x ;
}
int dcmp( double x ){
    if( fabs(x) < eps ) return 0 ;
    return ( x < 0 )? -1 : 1 ;
}
int segLineCross( Point a1 , Point a2 , Point b1 , Point b2 ){  
    int d1 = dcmp( det( a2 - a1 , b1 - a1 ) );
    int d2 = dcmp( det( a2 - a1 , b2 - a1 ) );
    //cout << d1 << ' ' << d2 << endl ;
    if( (d1^d2) == -2 ) 
        return 0 ;  
    if( d1 == 0 || d2 == 0 )  
        return 1 ;  
    return -1 ;  
}
Point p[maxn << 2] ;
bool check( Point a , Point b , int n ){
    if( dcmp( a.x - b.x ) == 0 && dcmp( a.y - b.y ) == 0 )
        return false ;
    for( int i = 1 ; i < 2 * n ; i += 2 ){
        if( segLineCross( a , b , p[i] , p[i+1] ) == -1 )
            return false ;
    }
    return true ;
}
bool work( int n ){
    for( int i = 1 ; i < 2 * n ; i++ ){
        for( int j = i + 1 ; j <= 2 * n ; j++ ){
            if( check( p[i] , p[j] , n ) )
                return true ;
        }
    }
    return false ;
}
int main(){
      //freopen("input.txt","r",stdin);
    int t ; cin >> t ;
    while( t-- ){
        int n ; cin >> n ;
        for( int i = 1 ; i <= 2 * n ; i++ ){
            cin >> p[i].x >> p[i].y ;
        }
        if( work( n ) )
            puts( "Yes!" ) ;
        else
            puts( "No!" ) ;
    }
    return 0;
}

POJ 1029 Intersecting Lines(直线相交)

题意:

判断两条直线相交还是平行,重合?

思路:

裸题,上模板A过去。

代码:

/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const double pi = acos( -1.0 ) ;
const double eps = 1e-8 ;
inline double sqr( double x ) { return x * x ; } 
inline int cmp( double x ){
    if( fabs(x) < eps ) return 0 ;
    if( x > 0 ) return 1 ;
    return -1 ;
}

struct Point{
    double x , y ;
    Point(){} ;
    Point( double a , double b ):x(a) , y(b){}
    void input(){
        scanf( "%lf%lf" , &x , &y ) ;
    }
    double norm(){
        return sqrt( sqr( x ) + sqr( y ) ) ;
    }
    friend Point operator + ( const Point &a , const Point &b ) { return Point( a.x + b.x , a.y + b.y ) ; }
    friend Point operator - ( const Point &a , const Point &b ) { return Point( a.x - b.x , a.y - b.y ) ; }
    friend Point operator * ( const Point &a , const double &b ) { return Point( a.x * b , a.y * b ) ; }
    friend Point operator * ( const double &a , const Point &b ) { return Point( b.x * a , b.y * a ) ; }
    friend Point operator / ( const Point &a , const double &b ) { return Point( a.x / b , a.y / b ) ; }
    friend bool operator == ( const Point &a , const Point &b ) { return cmp( a.x - b.x ) == 0 && cmp( a.y - b.y ) == 0 ; }
};
typedef Point Vector ;
double dot( const Point &a , const Point &b ){ return a.x * b.x + a.y * b.y ; }
double det( const Point &a , const Point &b ){ return a.x * b.y - a.y * b.x ; }
double dist( const Point &a , const Point &b ){ return ( a - b ).norm() ; }

struct Line{
    Point a , b ;
    Line(){}
    Line( Point x , Point y ): a(x) , b(y){}
};
bool parallel( Line a , Line b ){
    return !cmp( det( a.a - a.b , b.a - b.b ) ) ;
}
bool line_make_point( Line a , Line b , Point &res ){
    if( parallel( a , b ) ) return false ;
    double s1 = det( a.a - b.a , b.b - b.a ) ;
    double s2 = det( a.b - b.a , b.b - b.a ) ;
    res = ( s1 * a.b - s2 * a.a ) / ( s1 - s2 ) ;
    return true ;
}
double dis_to_line( Point P , Point A , Point B ){
    Vector v1 = B - A , v2 = P - A ;
    return fabs( det( v1 , v2 ) ) / v1.norm() ;
}

int main(){
  //freopen("input.txt","r",stdin);
    int n ; cin >> n ;
    puts("INTERSECTING LINES OUTPUT") ;
    while( n-- ){
        Point a1 , b1 , a2 , b2 ;
        a1.input() ;
        b1.input() ;
        a2.input() ;
        b2.input() ;
        Line l1( a1 , b1 ) , l2( a2 , b2 ) ;
        Point res ;
        if( parallel( l1 , l2 ) && !cmp(dis_to_line( l1.a , l2.a , l2.b )) )
            puts( "LINE" ) ;
        else if( parallel( l1 , l2 ) && cmp(dis_to_line( l1.a , l2.a , l2.b )) )
            puts( "NONE" ) ;
        else if( line_make_point( l1 , l2 , res ) ){
            printf( "POINT %.2f %.2f\n" , res.x , res.y ) ;
        }
    }
    puts( "END OF OUTPUT" ) ;
    return 0;
}

POJ 1556 The Doors(线段相交判定 + 最短路)

题意:

坐标系中有一个10*10的正方形房间,房间中有n面沿y轴方向的墙,每面墙上有两扇门,
求从房间最左边的(0,5)处到达房间最右边的(10,5)处的最短距离

思路:

可以算出,总共有4 * n+2个端点,其中包括入口与出口,以及3 * n条障碍线段,那么我们求出来所有点之间的距离,建立邻接矩阵,跑一遍flyod,dijkstra或者spfa都行,总之求出入口到出口的最短路即可。
至于建图方法,判断两个端点所成线段是否与任一障碍线段交,若相交那么距离无穷大,否则计算两点距离。

代码:

代码4500B,其中4000B是模板

/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const double inf = 10000000 ;
const double pi = acos( -1.0 ) ;
const double eps = 1e-8 ;
inline double sqr( double x ) { return x * x ; } 
inline int cmp( double x ){
    if( fabs(x) < eps ) return 0 ;
    if( x > 0 ) return 1 ;
    return -1 ;
}

struct Point{
    double x , y ;
    Point(){} ;
    Point( double a , double b ):x(a) , y(b){}
    void input(){
        scanf( "%lf%lf" , &x , &y ) ;
    }
    double norm(){
        return sqrt( sqr( x ) + sqr( y ) ) ;
    }
    friend Point operator + ( const Point &a , const Point &b ) { return Point( a.x + b.x , a.y + b.y ) ; }
    friend Point operator - ( const Point &a , const Point &b ) { return Point( a.x - b.x , a.y - b.y ) ; }
    friend Point operator * ( const Point &a , const double &b ) { return Point( a.x * b , a.y * b ) ; }
    friend Point operator * ( const double &a , const Point &b ) { return Point( b.x * a , b.y * a ) ; }
    friend Point operator / ( const Point &a , const double &b ) { return Point( a.x / b , a.y / b ) ; }
    friend bool operator == ( const Point &a , const Point &b ) { return cmp( a.x - b.x ) == 0 && cmp( a.y - b.y ) == 0 ; }
};
typedef Point Vector ;
double dot( const Point &a , const Point &b ){ return a.x * b.x + a.y * b.y ; }
double det( const Point &a , const Point &b ){ return a.x * b.y - a.y * b.x ; }
double dist( const Point &a , const Point &b ){ return ( a - b ).norm() ; }

struct Line{
    Point a , b ;
    Line(){}
    Line( Point x , Point y ): a(x) , b(y){}
};
bool segment_inter( Point a1 , Point a2 , Point b1 , Point b2 ){
    double c1 = det( a2 - a1 , b1 - a1 ) , c2 = det( a2 - a1 , b2 - a1 ) , 
           c3 = det( b2 - b1 , a1 - b1 ) , c4 = det( b2 - b1 , a2 - b1 ) ;
    bool tmp = ( ( cmp( c1 ) * cmp( c2 ) < 0 ) && ( cmp( c3 ) * cmp( c4 ) < 0 ) );
    return tmp ;
}
const int maxn = 205 ;
vector pt;
vector L;
bool v[maxn] ;
double G[maxn][maxn] ;
double dis[maxn] ;

void build( int n ){
    for( int i = 0 ; i < 4 * n + 2 ; i++ ){
        for( int j = 0 ; j < 4 * n + 2 ; j++ ){
            bool ok = true ;
            for( int k = 0 ; k < 3 * n ; k++ ){
                if( segment_inter( pt[i] , pt[j] , L[k].a , L[k].b ) ){
                    ok = false ;
                    break ;
                }
            }
            if( ok )
                G[i+1][j+1] = dist( pt[i] , pt[j] ) ;
            else
                G[i+1][j+1] = (double)inf ;
        }
    }
}
double dijkstra( int n ){
    for( int i = 1 ; i <= n ; i++ ) dis[i] = G[1][i] ;
    dis[1] = 0 ;
    cls( v ) ;
    for( int i = 1 ; i <= n ; i++ ){
        int mark = 1 ;
        double mindis = (double)inf ;
        for( int j = 1 ; j <= n ; j++ ){
            if( !v[j] && dis[j] < mindis ){
                mindis = dis[j] ;
                mark = j ;
            }
        }
        v[mark] = 1 ;
        for( int j = 1 ; j <= n ; j++ )
            if( !v[j] && G[mark][j] < inf )
                dis[j] = min( dis[j] , dis[mark] + G[mark][j] ) ;

    }
    return dis[n] ;
}
int main(){
  //freopen("input.txt","r",stdin);
    int n ;
    while( cin >> n && n > -1 ){
        pt.clear() ;
        L.clear() ;
        Point p( 0.0 , 5.0 ) ;
        pt.pb(p) ;
        for( int i = 1 ; i <= n ; i++ ){
            double x , y1 , y2 , y3 , y4 ;
            scanf( "%lf%lf%lf%lf%lf" , &x , &y1 , &y2 , &y3 , &y4 ) ;
            Point p1( x , y1 ) , p2( x , y2 ) , p3( x , y3 ) , p4( x , y4 ) ;
            pt.pb( p1 ) ; 
            pt.pb( p2 ) ; 
            pt.pb( p3 ) ; 
            pt.pb( p4 ) ; 
            L.pb( Line( Point( x , 0.0 ) , p1 ) ) ;
            L.pb( Line( p2 , p3 ) ) ;
            L.pb( Line( p4 , Point( x , 10.0 ) ) ) ;
        }
        pt.pb( Point( 10.0 , 5.0 ) ) ;
        build(n) ;
        double ans = dijkstra( 4*n + 2 ) ;
        printf( "%.2f\n" , ans ) ;
    }
    return 0;
}

POJ 1696 Space Ant(极角排序)

题意:

一只仅能左拐的蚂蚁,有n个点要去,要求设计爬行方案,使能去尽可能多的点,且保证爬行轨迹无交叉。

思路:

初见惊为神题,百思不得其解,后来知道了极角排序,发现实在是水题啊。。
先看样例1的图:

因为只能左拐,所以起点应尽可能在所有点的最下方,且最左边;

然后对于每一个点,下一个要去的点,要尽可能在以自己为原点,极角较小的方向上,即自己的“右边”,如果极角相同则选择较小距离的点。

然后照着模拟下去就行了,因为没有重点,所以一定可以走完所有点,方案其实就是画一个逆时针螺旋线遍历所有点。

代码:


/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const double pi = acos( -1.0 ) ;
const double eps = 1e-8 ;
inline double sqr( double x ) { return x * x ; } 
inline int cmp( double x ){
    if( fabs(x) < eps ) return 0 ;
    if( x > 0 ) return 1 ;
    return -1 ;
}

struct Point{
    double x , y ;
    Point(){} ;
    Point( double a , double b ):x(a) , y(b){}
    void input(){
        scanf( "%lf%lf" , &x , &y ) ;
    }
    double norm(){
        return sqrt( sqr( x ) + sqr( y ) ) ;
    }
    friend Point operator + ( const Point &a , const Point &b ) { return Point( a.x + b.x , a.y + b.y ) ; }
    friend Point operator - ( const Point &a , const Point &b ) { return Point( a.x - b.x , a.y - b.y ) ; }
    friend Point operator * ( const Point &a , const double &b ) { return Point( a.x * b , a.y * b ) ; }
    friend Point operator * ( const double &a , const Point &b ) { return Point( b.x * a , b.y * a ) ; }
    friend Point operator / ( const Point &a , const double &b ) { return Point( a.x / b , a.y / b ) ; }
    friend bool operator == ( const Point &a , const Point &b ) { return cmp( a.x - b.x ) == 0 && cmp( a.y - b.y ) == 0 ; }
};
typedef Point Vector ;
double dot( const Point &a , const Point &b ){ return a.x * b.x + a.y * b.y ; }
double det( const Point &a , const Point &b ){ return a.x * b.y - a.y * b.x ; }
double dist( const Point &a , const Point &b ){ return ( a - b ).norm() ; }

const int maxn = 55 ;
int pos ;
struct Poi{
    Point p ;
    int no ;
}last ;
vector p ;
int res[maxn] ;
bool acmp( const Poi &a , const Poi &b ){
    int tmp = cmp( det( a.p - last.p , b.p - last.p ) ) ;
    if( tmp != 0 ) return tmp > 0 ;
    return dist( a.p , last.p ) < dist( b.p ,last.p ) ;
}
bool lowcmp( const Poi &a , const Poi &b ){
    if( a.p.y != b.p.y ) return a.p.y < b.p.y ;
    return a.p.x < b.p.x ;
}

int main(){
    //freopen("input.txt","r",stdin);
    int t ; cin >> t ;
    while( t -- ){
        int n ; cin >> n ;
        for( int i = 1 ; i <= n ; i++ ){
            Poi t ;
            cin >> t.no >> t.p.x >> t.p.y ;
            p.pb( t ) ;
        }
        sort( p.begin() , p.end() , lowcmp ) ;
        vector::iterator it = p.begin() ;
        last = *it ;
        p.erase( p.begin() ) ;
        printf( "%d %d" , n , last.no ) ;
        for( int i = 1 ; i < n ; i++ ){
            sort( p.begin() , p.end() , acmp ) ;
            it = p.begin() ;
            last = *it ;
            p.erase( p.begin() ) ;
            printf( " %d" , last.no ) ;
        }
        puts("") ;
    }
    return 0;
}


POJ1066 Treasure Hunt(线段相交)

题意:

一个房间被n面墙分成多个密室,告知宝藏坐标,求最少要炸几面墙才能取到宝藏。

思路:

其实也算一个大水题,枚举每一面墙的端点与宝藏点所成线段,与所有墙判断是否相交,相交+1,维护最小值,输出的时候+1即可。
ps.注意n = 0 .

代码:

/*
 * @author FreeWifi_novicer
 * language : C++/C
 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const double pi = acos( -1.0 ) ;
const double eps = 1e-8 ;
inline double sqr( double x ) { return x * x ; } 
inline int cmp( double x ){
    if( fabs(x) < eps ) return 0 ;
    if( x > 0 ) return 1 ;
    return -1 ;
}

struct Point{
    double x , y ;
    Point(){} ;
    Point( double a , double b ):x(a) , y(b){}
    void input(){
        scanf( "%lf%lf" , &x , &y ) ;
    }
    double norm(){
        return sqrt( sqr( x ) + sqr( y ) ) ;
    }
    friend Point operator + ( const Point &a , const Point &b ) { return Point( a.x + b.x , a.y + b.y ) ; }
    friend Point operator - ( const Point &a , const Point &b ) { return Point( a.x - b.x , a.y - b.y ) ; }
    friend Point operator * ( const Point &a , const double &b ) { return Point( a.x * b , a.y * b ) ; }
    friend Point operator * ( const double &a , const Point &b ) { return Point( b.x * a , b.y * a ) ; }
    friend Point operator / ( const Point &a , const double &b ) { return Point( a.x / b , a.y / b ) ; }
    friend bool operator == ( const Point &a , const Point &b ) { return cmp( a.x - b.x ) == 0 && cmp( a.y - b.y ) == 0 ; }
};
typedef Point Vector ;
double dot( const Point &a , const Point &b ){ return a.x * b.x + a.y * b.y ; }
double det( const Point &a , const Point &b ){ return a.x * b.y - a.y * b.x ; }
double dist( const Point &a , const Point &b ){ return ( a - b ).norm() ; }
struct Line{
    Point a , b ;
    Line(){}
    Line( Point x , Point y ): a(x) , b(y){}
};
bool segment_inter( Point a1 , Point a2 , Point b1 , Point b2 ){
    double c1 = det( a2 - a1 , b1 - a1 ) , c2 = det( a2 - a1 , b2 - a1 ) , 
           c3 = det( b2 - b1 , a1 - b1 ) , c4 = det( b2 - b1 , a2 - b1 ) ;
    return cmp( c1 ) * cmp( c2 ) < 0 && cmp( c3 ) * cmp( c4 ) < 0 ;
}

const int maxn = 35 ;
Line L[maxn] ;
int main(){
    //freopen("input.txt","r",stdin);
    int n ; 
    while( cin >> n ){
        for( int i = 1 ; i <= n ; i++ ){
            L[i].a.input() ;
            L[i].b.input() ;
        }
        Point p ;
        p.input() ;
        if( !n ){
            printf( "Number of doors = 1\n" ) ;
            continue ;
        }
        int cnt = 0 ;
        int ans = 1000000 ;
        for( int i = 1 ; i <= n ; i++ ){
            cnt = 0 ;
            for( int j = 1 ; j <= n ; j++ ){
                if( segment_inter( L[i].a , p , L[j].a , L[j].b ) ) cnt++ ;
            }
            ans = min( ans , cnt ) ;
            cnt = 0 ;
            for( int j = 1 ; j <= n ; j++ ){
                if( segment_inter( L[i].b , p , L[j].a , L[j].b ) ) cnt++ ;
            }
            ans = min( ans , cnt ) ;
        }
        ans ++ ;
        cout << "Number of doors = " << ans << endl ;
    }
    return 0;
}

POJ 2826 An Easy Problem?!(分类讨论,灵活运用叉积)

题意:

输入两块木板的截面坐标,求能收集多少雨水。

思路:

比较恶心的分类讨论。
主要的坑就是:
共线判断,
输出要加eps(可能输出-0.00。
多想想,想清楚。
附赠数据一组:
1
68.22 191.66 257.23 104.97
140.25 33.53 56.71 302.58
正确输出是0.00

代码:

/*
 * @author FreeWifi_novicer
 * language : C++/C
 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const double pi = acos( -1.0 ) ;
const double eps = 1e-8 ;
inline double sqr( double x ) { return x * x ; } 
inline int cmp( double x ){
    if( fabs(x) < eps ) return 0 ;
    if( x > 0 ) return 1 ;
    return -1 ;
}

struct Point{
    double x , y ;
    Point(){} ;
    Point( double a , double b ):x(a) , y(b){}
    void input(){
        scanf( "%lf%lf" , &x , &y ) ;
    }
    double norm(){
        return sqrt( sqr( x ) + sqr( y ) ) ;
    }
    friend Point operator + ( const Point &a , const Point &b ) { return Point( a.x + b.x , a.y + b.y ) ; }
    friend Point operator - ( const Point &a , const Point &b ) { return Point( a.x - b.x , a.y - b.y ) ; }
    friend Point operator * ( const Point &a , const double &b ) { return Point( a.x * b , a.y * b ) ; }
    friend Point operator * ( const double &a , const Point &b ) { return Point( b.x * a , b.y * a ) ; }
    friend Point operator / ( const Point &a , const double &b ) { return Point( a.x / b , a.y / b ) ; }
    friend bool operator == ( const Point &a , const Point &b ) { return cmp( a.x - b.x ) == 0 && cmp( a.y - b.y ) == 0 ; }
};
typedef Point Vector ;
double dot( const Point &a , const Point &b ){ return a.x * b.x + a.y * b.y ; }
double det( const Point &a , const Point &b ){ return a.x * b.y - a.y * b.x ; }
double dist( const Point &a , const Point &b ){ return ( a - b ).norm() ; }

struct Line{
    Point a , b ;
    Line(){}
    Line( Point x , Point y ): a(x) , b(y){}
};
Point line_make_point( Line a , Line b ){
    double s1 = det( a.a - b.a , b.b - b.a ) ;
    double s2 = det( a.b - b.a , b.b - b.a ) ;
    Point res = ( s1 * a.b - s2 * a.a ) / ( s1 - s2 ) ;
    return res ;
}
bool segment_inter( Point a1 , Point a2 , Point b1 , Point b2 ){
    double c1 = det( a2 - a1 , b1 - a1 ) , c2 = det( a2 - a1 , b2 - a1 ) , 
           c3 = det( b2 - b1 , a1 - b1 ) , c4 = det( b2 - b1 , a2 - b1 ) ;
    return cmp( c1 ) * cmp( c2 ) <= 0 && cmp( c3 ) * cmp( c4 ) <= 0 ;
}

int main(){
    //freopen("my.in","r",stdin);
    //freopen("my.out","w+",stdout);
    //freopen("input.txt","r",stdin);
    int t ; cin >> t ;
    while( t-- ){
        Line b1 , b2 ;
        b1.a.input() ; b1.b.input() ;
        if( b1.b.y < b1.a.y ) swap( b1.a , b1.b ) ;
        b2.a.input() ; b2.b.input() ;
        if( b2.b.y < b2.a.y ) swap( b2.a , b2.b ) ;
        if( b1.b.x > b2.b.x ) swap( b1 , b2 ) ;
        if( !segment_inter( b1.a , b1.b , b2.a , b2.b ) ){
            printf( "0.00\n" ) ;
            continue ;
        }
        double ans ;
        Point p = line_make_point( b1 , b2 ) ;
        if( b1.b.y < b2.b.y ){
            Line h1( b1.b , Point( b1.b.x , b1.b.y + 1000000 ) ) ;
            if( segment_inter( h1.a , h1.b , p , b2.b ) ){
                printf( "0.00\n" ) ;
                continue ;
            }
            else{
                if( cmp( det( b1.b - p , b2.b - p ) ) > 0 ){
                    Line h2( b2.b , Point( b2.b.x , b2.b.y - 1000000 ) ) ;
                    Point pp = line_make_point( h2 , b1 ) ;
                    ans = fabs( det( b2.b - p , pp - p ) / 2.0 ) ;
                }
                else if( cmp( det( b1.b - p , b2.b - p ) ) < 0 ){
                    Line h3( b1.b , Point( b1.b.x + 1000000 , b1.b.y ) ) ;
                    Point pp = line_make_point( h3 , b2 ) ;
                    ans = fabs( det( b1.b - p , pp - p ) / 2.0 ) ;
                }
                else{
                    printf( "0.00\n" ) ;
                    continue ;
                }
            }
        }
        else if( b1.b.y > b2.b.y ){
            Line h1( b2.b , Point( b2.b.x , b2.b.y + 1000000 ) ) ;
            if( segment_inter( h1.a , h1.b , p , b1.b ) ){
                printf( "0.00\n" ) ;
                continue ;
            }
            else{
            if( cmp( det( b1.b - p , b2.b - p ) ) > 0 ){
                Line h2( b2.b , Point( b2.b.x , b2.b.y - 1000000 ) ) ;
                Point pp = line_make_point( h2 , b1 ) ;
                ans = fabs( det( b2.b - p , pp - p ) / 2.0 ) ;
            }
            else if( cmp( det( b1.b - p , b2.b - p ) ) < 0 ){
                Line h3( b2.b , Point( b2.b.x - 1000000 , b2.b.y ) ) ;
                Point pp = line_make_point( h3 , b1 ) ;
                ans = fabs( det( b2.b - p , pp - p ) / 2.0 ) ;
            }
            else{
                printf( "0.00\n" ) ;
                continue ;
            }
        }
        }
        else if( cmp( b1.b.y - b2.b.y ) == 0 ){
            ans = fabs( det( b2.b - p , b1.b - p ) / 2.0 ) ;
        }
        if( ans > 0 - eps )
            printf( "%.2f\n" , ans + eps ) ;
        else{
            printf( "%.2f\n" , 0.00 + eps ) ;
        }
    }
    return 0;
}

POJ 1410 Intersection(线段相交的种种情况)

题意:

输入一条线段的两个端点,一个矩形的两个顶点,判断线段与矩形是否相交(矩形包括4条边与边内区域)

思路:

从题目本身来说是个大水题。。但很考验模板的准确性。
判断为true有这么几种:

  1. 线段与四条边相交,包括端点相交
  2. 线段在矩形内
  3. 线段与四条边重叠共线或首尾相接

其实这题考虑不相交的情况可以简洁许多,至少从代码量上来说是这样的

强烈推荐试试这两组样例
0 18 8 12 1 1 11 11 -> F
9 7 9 2 4 3 9 6 -> T

代码:

/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;


const double pi = acos( -1.0 ) ;
const double eps = 1e-8 ;
inline double sqr( double x ) { return x * x ; } 
inline int cmp( double x ){
    if( fabs(x) < eps ) return 0 ;
    if( x > 0 ) return 1 ;
    return -1 ;
}

struct Point{
    double x , y ;
    Point(){} ;
    Point( double a , double b ):x(a) , y(b){}
    void input(){
        scanf( "%lf%lf" , &x , &y ) ;
    }
    double norm(){
        return sqrt( sqr( x ) + sqr( y ) ) ;
    }
    friend Point operator + ( const Point &a , const Point &b ) { return Point( a.x + b.x , a.y + b.y ) ; }
    friend Point operator - ( const Point &a , const Point &b ) { return Point( a.x - b.x , a.y - b.y ) ; }
    friend Point operator * ( const Point &a , const double &b ) { return Point( a.x * b , a.y * b ) ; }
    friend Point operator * ( const double &a , const Point &b ) { return Point( b.x * a , b.y * a ) ; }
    friend Point operator / ( const Point &a , const double &b ) { return Point( a.x / b , a.y / b ) ; }
    friend bool operator == ( const Point &a , const Point &b ) { return cmp( a.x - b.x ) == 0 && cmp( a.y - b.y ) == 0 ; }
};
typedef Point Vector ;
double dot( const Point &a , const Point &b ){ return a.x * b.x + a.y * b.y ; }
double det( const Point &a , const Point &b ){ return a.x * b.y - a.y * b.x ; }
double dist( const Point &a , const Point &b ){ return ( a - b ).norm() ; }

struct Line{
    Point a , b ;
    Line(){}
    Line( Point x , Point y ): a(x) , b(y){}
};
bool Onsegment( Point p , Point s , Point t ){
    return cmp( det( p - s , t - s ) ) == 0 && cmp( dot( p - s , p - t ) ) <= 0 ;
}
bool parallel( Line a , Line b ){
    return !cmp( det( a.a - a.b , b.a - b.b ) ) ;
}
bool segment_inter( Point a1 , Point a2 , Point b1 , Point b2 ){
    double c1 = det( a2 - a1 , b1 - a1 ) , c2 = det( a2 - a1 , b2 - a1 ) , 
           c3 = det( b2 - b1 , a1 - b1 ) , c4 = det( b2 - b1 , a2 - b1 ) ;
    return cmp( c1 ) * cmp( c2 ) < 0 && cmp( c3 ) * cmp( c4 ) < 0 ;
}

int main(){
  //freopen("input.txt","r",stdin);
    int t ; cin >> t ;
    while( t-- ){
        Line s ;
        s.a.input() ; s.b.input() ;
        Point top , bot ;
        top.input() ; bot.input() ;
        if( bot.x < top.x ){
            swap( bot.x , top.x ) ;
        }
        if( bot.y > top.y ){
            swap( bot.y , top.y ) ;
        }
        Line r1( top , Point( top.x , bot.y ) ) , r2( Point( bot.x , top.y ) , bot ) ;
        Line r3( top , Point( bot.x , top.y ) ) , r4( Point( top.x , bot.y ) , bot ) ;
        bool ok = false ;
        if( segment_inter( r1.a , r1.b , s.a , s.b ) )
            ok = true ;
        if( segment_inter( r2.a , r2.b , s.a , s.b ) )
            ok = true ;
        if( segment_inter( r3.a , r3.b , s.a , s.b ) )
            ok = true ;
        if( segment_inter( r4.a , r4.b , s.a , s.b ) )
            ok = true ;
        if( Onsegment( s.a , r1.a , r1.b ) || Onsegment( s.b , r1.a , r1.b ) )
            ok = true ;
        if( Onsegment( s.a , r2.a , r2.b ) || Onsegment( s.b , r2.a , r2.b ) )
            ok = true ;
        if( Onsegment( s.a , r3.a , r3.b ) || Onsegment( s.b , r3.a , r3.b ) )
            ok = true ;
        if( Onsegment( s.a , r4.a , r4.b ) || Onsegment( s.b , r4.a , r4.b ) )
            ok = true ;
        if( parallel( s , r1 ) && s.a.x == r1.a.x ){
            if( s.a.y >= min( r1.a.y , r1.b.y ) &&  s.a.y <= max( r1.a.y , r1.b.y ) )
                ok = true ;
            if( s.b.y >= min( r1.a.y , r1.b.y ) &&  s.b.y <= max( r1.a.y , r1.b.y ) )
                ok = true ;
            if( s.a.y <= min( r1.a.y , r1.b.y ) &&  s.b.y >= max( r1.a.y , r1.b.y ) )
                ok = true ;
            if( s.b.y <= min( r1.a.y , r1.b.y ) &&  s.a.y >= max( r1.a.y , r1.b.y ) )
                ok = true ;
        }
        if( parallel( s , r2 ) && s.a.x == r2.a.x ){
            if( s.a.y >= min( r2.a.y , r2.b.y ) &&  s.a.y <= max( r2.a.y , r2.b.y ) )
                ok = true ;
            if( s.b.y >= min( r2.a.y , r2.b.y ) &&  s.b.y <= max( r2.a.y , r2.b.y ) )
                ok = true ;
            if( s.a.y <= min( r2.a.y , r2.b.y ) &&  s.b.y >= max( r2.a.y , r2.b.y ) )
                ok = true ;
            if( s.b.y <= min( r2.a.y , r2.b.y ) &&  s.a.y >= max( r2.a.y , r2.b.y ) )
                ok = true ;
        }
        if( parallel( s , r3 ) && s.a.y == r3.a.y ){
            if( s.a.x >= min( r3.a.x , r3.b.x ) &&  s.a.x <= max( r3.a.x , r3.b.x ) )
                ok = true ;
            if( s.b.x >= min( r3.a.x , r3.b.x ) &&  s.b.x <= max( r3.a.x , r3.b.x ) )
                ok = true ;
            if( s.a.x <= min( r3.a.x , r3.b.x ) &&  s.b.x >= max( r3.a.x , r3.b.x ) )
                ok = true ;
            if( s.b.x <= min( r3.a.x , r3.b.x ) &&  s.a.x >= max( r3.a.x , r3.b.x ) )
                ok = true ;
        }
        if( parallel( s , r4 ) && s.a.y == r4.a.y ){
            if( s.a.x >= min( r4.a.x , r4.b.x ) &&  s.a.x <= max( r4.a.x , r4.b.x ) )
                ok = true ;
            if( s.b.x >= min( r4.a.x , r4.b.x ) &&  s.b.x <= max( r4.a.x , r4.b.x ) )
                ok = true ;
            if( s.a.x <= min( r4.a.x , r4.b.x ) &&  s.b.x >= max( r4.a.x , r4.b.x ) )
                ok = true ;
            if( s.b.x <= min( r4.a.x , r4.b.x ) &&  s.a.x >= max( r4.a.x , r4.b.x ) )
                ok = true ;
        }
        if( top.x <= min( s.a.x , s.b.x ) 
                && top.y >= max( s.a.y , s.b.y ) 
                && bot.y <= min( s.a.y , s.b.y ) 
                && bot.x >= max( s.a.x , s.b.x ) )
            ok = true ;
        if( ok )
            puts( "T" ) ;
        else
            puts( "F" ) ;
    }
    return 0;
}

POJ 2074 Line of Sight(直线交点+区间并)

题意:

在房子里看路的视线可能会被障碍物挡住,问从这条路上能看到完整路的最大长度。

思路:

盲区范围:房子的左端点与障碍物的右端点所成直线与路的交点p1,房子的右端点与障碍物的左端点所成直线与路的交点p2.盲区即为p2到p1的范围。
求出所有的盲区范围,把所有盲区线段按左端点的x坐标升序排序,然后从左到右扫一遍,维护i之前所有线段的最右端的x坐标last。如果第i个盲区的左端点大于last,那么last到i的左端点的这片区域都是不被覆盖的。扫描每个线段时更新last。
注意障碍物不一定在路与房子之间。

代码:

/*
 * @author FreeWifi_novicer
 * language : C++/C
 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const double pi = acos( -1.0 ) ;
const double eps = 1e-8 ;
inline double sqr( double x ) { return x * x ; } 
inline int cmp( double x ){
    if( fabs(x) < eps ) return 0 ;
    if( x > 0 ) return 1 ;
    return -1 ;
}

struct Point{
    double x , y ;
    Point(){} ;
    Point( double a , double b ):x(a) , y(b){}
    void input(){
        scanf( "%lf%lf" , &x , &y ) ;
    }
    double norm(){
        return sqrt( sqr( x ) + sqr( y ) ) ;
    }
    friend Point operator + ( const Point &a , const Point &b ) { return Point( a.x + b.x , a.y + b.y ) ; }
    friend Point operator - ( const Point &a , const Point &b ) { return Point( a.x - b.x , a.y - b.y ) ; }
    friend Point operator * ( const Point &a , const double &b ) { return Point( a.x * b , a.y * b ) ; }
    friend Point operator * ( const double &a , const Point &b ) { return Point( b.x * a , b.y * a ) ; }
    friend Point operator / ( const Point &a , const double &b ) { return Point( a.x / b , a.y / b ) ; }
    friend bool operator == ( const Point &a , const Point &b ) { return cmp( a.x - b.x ) == 0 && cmp( a.y - b.y ) == 0 ; }
};
typedef Point Vector ;
double dot( const Point &a , const Point &b ){ return a.x * b.x + a.y * b.y ; }
double det( const Point &a , const Point &b ){ return a.x * b.y - a.y * b.x ; }
double dist( const Point &a , const Point &b ){ return ( a - b ).norm() ; }

struct Line{
    Point a , b ;
    Line(){}
    Line( Point x , Point y ): a(x) , b(y){}
};
Point line_make_point( Line a , Line b ){
    double s1 = det( a.a - b.a , b.b - b.a ) ;
    double s2 = det( a.b - b.a , b.b - b.a ) ;
    Point res = ( s1 * a.b - s2 * a.a ) / ( s1 - s2 ) ;
    return res ;
}
bool cmp1( Line l1 , Line l2 ){
    if( cmp( l1.a.x - l2.a.x ) != 0 )
        return l1.a.x < l2.a.x ;
    return l1.b.x < l2.b.x ;
}
vectorlight ;
int main(){
    //freopen("input.txt","r",stdin);
    double x1 , x2 , y ;
    while( cin >> x1 >> x2 >> y ){
        if( !x1 && !x2 && !y ) break ;
        light.clear() ;
        if( x1 > x2 ) swap( x1 , x2 ) ;
        Line h( Point( x1 , y ) , Point( x2 , y ) ) ;
        cin >> x1 >> x2 >> y ;
        Line l( Point( x1 , y ) , Point( x2 , y ) ) ;
        int n ;
        cin >> n ;
        if( n == 0 ){
            printf( "%.2f\n" , x2 - x1 ) ;
            continue ;
        }
        for( int i = 1 ; i <= n ; i++ ){
            scanf( "%lf%lf%lf" , &x1 , &x2 , &y ) ;
            if( y > h.a.y - eps || y < l.a.y + eps ) continue ;
            if( x1 > x2 ) swap( x1 , x2 ) ;
            Line H( Point( x1 , y ) , Point( x2 , y ) ) ;
            Point p1 = line_make_point( Line( h.a , H.b ) , l ) ;
            if( p1.x < l.a.x ) p1.x = l.a.x ;
            if( p1.x > l.b.x ) p1.x = l.b.x ;
            Point p2 = line_make_point( Line( h.b , H.a ) , l ) ;
            if( p2.x < l.a.x ) p2.x = l.a.x ;
            if( p2.x > l.b.x ) p2.x = l.b.x ;
            if( cmp( p1.x - p2.x ) == 0 ) continue ;
            else{
                light.pb( Line( p2 , p1 ) ) ;
            }
        }
        sort( light.begin() , light.end() , cmp1 ) ;
        int s = light.size() ;
        if( light.empty() ){
            printf( "%.2f\n" , l.b.x - l.a.x ) ;
            continue ;
        }
        double ans = 0 , last = 0 ; 
        for( int i = 0 ; i < s ; i++ ){
            if( light[i].a.x > last ){
                ans = max( ans , light[i].a.x - last ) ;
                last = light[i].b.x ;
            }
            else {
                last = max( last , light[i].b.x ) ;
            }
        }
        ans = max( ans , l.b.x - last ) ;
        if( !cmp( ans ) )
            puts( "No View" ) ;
        else
            printf( "%.2f\n" , ans ) ;
    }
    return 0;
}

你可能感兴趣的:(计算几何-线段,ACM,and,novicer)