题目分析:状态太差了。。这题花了好久才写出来。。
题目倒是很简单,直接枚举边的起点u,终点v,看是否能够沿着直线从u走到v,如果可以则建边u-v,最后最短路即可。并且因为本题是DAG图,所以可以DP。
代码如下:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define REP( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define REV( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define CLR( a , x ) memset ( a , x , sizeof a )
const int MAXN = 1000 ;
const int MAXE = 100000 ;
const double eps = 1e-6 ;
const double INF = 1e10 ;
struct Point {
double x , y ;
Point () {}
Point ( double x , double y ) : x ( x ) , y ( y ) {}
Point operator - ( const Point& p ) const {
return Point ( x - p.x , y - p.y ) ;
}
} p[MAXN] ;
struct Edge {
int v ;
double c ;
Edge* next ;
} E[MAXE] , *H[MAXN] , *cur ;
int n ;
int Q[MAXN] , head , tail ;
int in[MAXN] ;
double d[MAXN] ;
void clear () {
cur = E ;
CLR ( in , 0 ) ;
CLR ( H , 0 ) ;
}
void addedge ( int u , int v , double c ) {
cur -> v = v ;
cur -> c = c ;
cur -> next = H[u] ;
H[u] = cur ++ ;
}
double Cross ( const Point& a , const Point& b ) {
return a.x * b.y - a.y * b.x ;
}
double dist ( Point a ) {
return sqrt ( a.x * a.x + a.y * a.y ) ;
}
bool Intersect ( Point a1 , Point a2 , Point b1 , Point b2 ) {
if ( Cross ( a1 - a2 , b1 - a2 ) * Cross ( a1 - a2 , b2 - a2 ) <= eps ) return 1 ;
return 0 ;
}
bool check ( Point a1 , Point a2 , int low , int high ) {
REP ( i , low , high )
if ( !Intersect ( a1 , a2 , p[i * 4 + 1] , p[i * 4 + 2] )
&& !Intersect ( a1 , a2 , p[i * 4 + 3] , p[i * 4 + 4] ) ) return 0 ;
return 1 ;
}
void topo () {
FOR ( i , 1 , n * 4 + 1 ) d[i] = INF ;
head = tail = 0 ;
FOR ( i , 0 , n * 4 + 1 ) if ( !in[i] ) Q[tail ++] = i ;
d[0] = 0 ;
while ( head != tail ) {
int u = Q[head ++] ;
travel ( e , H , u ) {
int v = e -> v ;
if ( -- in[v] == 0 ) Q[tail ++] = v ;
if ( d[v] > d[u] + e -> c ) d[v] = d[u] + e -> c ;
}
}
}
void solve () {
double x ;
clear () ;
p[0].x = 0 ;
p[0].y = 5 ;
p[n * 4 + 1].x = 10 ;
p[n * 4 + 1].y = 5 ;
REP ( i , 0 , n ) {
scanf ( "%lf" , &x ) ;
REP ( j , 1 , 5 ) {
scanf ( "%lf" , &p[i * 4 + j].y ) ;
p[i * 4 + j].x = x ;
}
}
if ( check ( p[0] , p[n * 4 + 1] , 0 , n ) ) {
printf ( "10.00\n" ) ;
return ;
}
REP ( i , 0 , n ) {
REP ( j , 1 , 5 ) {
if ( check ( p[0] , p[i * 4 + j] , 0 , i ) ) {
addedge ( 0 , i * 4 + j , dist ( p[0] - p[i * 4 + j] ) ) ;
in[i * 4 + j] ++ ;
}
if ( check ( p[n * 4 + 1] , p[i * 4 + j] , i + 1 , n ) ) {
addedge ( i * 4 + j , n * 4 + 1 , dist ( p[n * 4 + 1] - p[i * 4 + j] ) ) ;
in[n * 4 + 1] ++ ;
}
REP ( k , i + 1 , n )
REP ( l , 1 , 5 )
if ( check ( p[i * 4 + j] , p[k * 4 + l] , i + 1 , k ) ) {
addedge ( i * 4 + j , k * 4 + l , dist ( p[i * 4 + j] - p[k * 4 + l] ) ) ;
in[k * 4 + l] ++ ;
}
}
}
topo () ;
printf ( "%.2f\n" , d[n * 4 + 1] ) ;
}
int main () {
while ( ~scanf ( "%d" , &n ) && ~n ) solve () ;
return 0 ;
}