先利用线段相交,判断可以建立的边,然后求存最短路即可
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> #define eps 1e-6 #define MAX 10007 using namespace std; int n; struct Point { double x , y; }point[MAX][10]; int sig ( double d ) { return fabs(d) < eps ? 0 : d<0? -1 : 1 ; } double cross ( Point&o , Point &a , Point& b ) { return (a.x-o.x)*(b.y-o.y)-(b.x-o.x)*(a.y-o.y); } bool segCross ( Point &a , Point &b , Point &c , Point &d ) { double s1,s2; int d1 , d2 , d3 , d4; d1 = sig(s1=cross(a,b,c)); d2 = sig(s2=cross(a,b,d)); d3 = sig(cross(c,d,a)); d4 = sig(cross(c,d,b)); if ((d1^d2)==-2 && (d3^d4)==-2) return 1; return 0; } struct edge { int u,v,next; double w; }e[MAX]; int head[MAX]; int cc = 0; void add ( int u , int v , double w ) { e[cc].u = u; e[cc].v = v; e[cc].next = head[u]; e[cc].w = w; head[u] = cc++; } bool check ( Point& a , Point &b , int begin , int end ) { for ( int i = begin+1 ; i < end ; i++ ) for ( int j = 1 ; j < 6 ; j += 2 ) if ( segCross ( a , b , point[i][j] , point[i][j+1] ) ) return false; return true; } double dis ( Point& a , Point& b ) { return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2)); } double way[MAX]; bool used[MAX]; void spfa ( int s = 1 , int v = 6*n+7 ) { queue<int> q; memset ( used , 0 , sizeof ( used ) ); q.push ( s ); used[s] = 1; for ( int i = s ; i <= v ; i++ ) way[i] = 1e9; way[s] = 0; while ( !q.empty( ) ) { int id = q.front(); q.pop(); used[id] = false; for ( int i = head[id] ; i != -1 ; i = e[i].next ) { int v = e[i].v; if ( way[v] > way[id] + e[i].w ) { way[v] = way[id] + e[i].w; if ( used[v] ) continue; used[v] = true; q.push ( v ); } } } } int main ( ) { double x; while ( ~scanf ( "%d" , &n ) ) { if ( n == -1 ) break; cc = 0; memset ( head , -1 , sizeof ( head ) ); for ( int i = 1 ; i <= n ; i++ ) { scanf ( "%lf" , &x ); for ( int j = 1 ; j <= 6 ; j++ ) { point[i][j].x = x; if ( j == 1 ) point[i][j].y = 0.0; else if( j == 6 ) point[i][j].y = 10.0; else scanf ( "%lf" , &point[i][j].y ) ; } } for ( int i = 1 ; i <= n ; i++ ) for ( int j = 1 ; j <= 6 ; j++ ) for ( int k = i+1 ; k <= n ; k++ ) for ( int t = 1 ; t <= 6 ; t++ ) { if ( i==k && j == t ) continue; if ( check(point[i][j] , point[k][t], i , k )) add ( i*6+j , k*6+t , dis( point[i][j] , point[k][t] )); } Point start,end; start.x = 0.0 , start.y = 5.0; end.x = 10.0 , end.y = 5.0; if ( check ( start , end , 0 , n+1 ) ) add ( 1 , n*6+7 , 10.0 ); for ( int i = 1 ; i <= n ; i++ ) for ( int j = 1 ; j <= 6 ; j++ ) { if ( check( start , point[i][j] ,0, i ) ) add ( 1 , i*6+j , dis ( start , point[i][j] ) ); if ( check ( point[i][j], end , i , n+1 ) ) add ( i*6+j , n*6+7 , dis ( point[i][j] , end ) ); } spfa ( ); /* for ( int i = 1 ; i <= 6*n+7 ; i++ ) printf ( "%lf " , way[i] ); cout << endl;*/ /* for ( int i = 0 ; i < cc ; i++ ) cout << e[i].u<< " " << e[i].v << " " << e[i].w << endl;*/ printf ( "%.2f\n" , way[n*6+7] ); } }