先利用线段相交,判断可以建立的边,然后求存最短路即可
#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] );
}
}