计算几何入门题#1(点,线基本关系,点积叉积的理解)
2015-09-03 23:58
357 查看
POJ 2318(叉积判左右)
题意:
给一个有很多隔栏的箱子以及一些玩具的坐标,求箱子每个区域内玩具个数。思路:
其实就是二分+叉积判断。通过二分隔栏线段,得到一个玩具所在区域。
玩具(x,y)所在区域的判断方式是与左边隔栏叉积小于0,右边大于0.
第一次真正意义上做计算几何的题,对叉积理解还不够充分,连WA好多发,啊。。
代码:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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 = l = 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了它。。代码:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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 = l = 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 (判断线段直线相交)
题意:
输入一些线段,问是否存在一条直线使所有线段在直线上的投影都有公共点。思路:
若存在一条直线使所有线段在直线上的投影都有公共点,等价于存在一条直线与所有线段相交。证明:
存在一条直线使所有线段在直线上的投影都有公共点,作这条直线的垂线,则垂线与所有线段相交。
枚举所有线段的两个端点连成直线,若这条直线经过所有线段,则存在一条直线与所有线段相交。
证明:若存在一条直线与所有线段相交,则可保持该直线与所有线段相交,将其平移至交于某一端点,再旋转该线段,使其交于第二个端点。
代码:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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过去。代码:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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是模板[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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<Point> pt; vector<Line> 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 ; } 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的图:
因为只能左拐,所以起点应尽可能在所有点的最下方,且最左边;
然后对于每一个点,下一个要去的点,要尽可能在以自己为原点,极角较小的方向上,即自己的“右边”,如果极角相同则选择较小距离的点。
然后照着模拟下去就行了,因为没有重点,所以一定可以走完所有点,方案其实就是画一个逆时针螺旋线遍历所有点。
代码:
[code] /* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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<Poi> 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<Poi>::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 .
代码:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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
代码:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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有这么几种:
线段与四条边相交,包括端点相交
线段在矩形内
线段与四条边重叠共线或首尾相接
其实这题考虑不相交的情况可以简洁许多,至少从代码量上来说是这样的
强烈推荐试试这两组样例
0 18 8 12 1 1 11 11 -> F
9 7 9 2 4 3 9 6 -> T
代码:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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。
注意障碍物不一定在路与房子之间。
代码:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> 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 ; } vector<Line>light ; 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; }
相关文章推荐
- MFC打包程序(一)
- 修饰符 static extern const (转载)
- 自学QT之实现窗口分割QSplitter的使用
- windowsphone8.1学习笔记之Toast通知
- 我参与的一个项目的继续总结:技术篇
- run junit :java.lang.NoClassDefFoundError: org/junit/runners/model/MultipleFailureException
- 关于json数据解析
- [BZOJ4199][Noi2015]品酒大会
- ipvsadm两种安装方式
- sublime使用
- Java HashMap 深入 内部解析
- safari 插件(如Xmarks)的设置、登陆、禁用等
- yield关键字的使用
- delphi json用法
- Linux上vi(vim)的使用教程
- 黑马程序员————java基础————常用类String类
- HDU1561 树型DP入门
- linux配置IP地址
- Linux禁止ping以及开启ping的方法
- appium源码分析(十)-GetAttribute