The Doors
思路 这个题最难的就是建图了,建图之后求个最短路也就出来了,说下我的建图方法,首先我用pos[ ] 数组将起点和终点以及每个墙线段的端点作为图的顶点(去除墙根的两个点,因为没有意义)。然后用 seg[][]数组表示每个墙的各个线段的信息,seg[i][] 表示第i个墙的信息,这个数组的目的主要是为了:遍历pos[]数组的每两个点判断是否能建边,如果这两个点形成的线段被之间的墙挡住了(与该墙中某一个线段相交),就无法建边,否则建边。 这里我再说一下判断线段a-b和c-d是否相交如何判断? 如果两条线段相交,有 c a ⃗ × c b ⃗ \vec{ca}\times\vec{cb} c a
× c b
和 d a ⃗ × d b ⃗ \vec{da}\times\vec{db} d a
× d b
异号并且 d a ⃗ × c a ⃗ \vec{da}\times\vec{ca} d a
× c a
和 d b ⃗ × c b ⃗ \vec{db}\times\vec{cb} d b
× c b
也是异号,这两个条件同时满足才是相交,我只写了满足一个条件就可以了,但这并不是判断线段相交的充分条件,这是因为本题题意数据给出的特殊,希望大家知道就好。
代码
#pragma GCC optimize(2)
#include <iostream>
#include <cstdio>
#include <queue>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second
#define scf scanf
#define prf printf
typedef pair< double , int > pa;
const double INF= 0x3f3f3f3f ;
const double eps= 1e-8 ;
const int MAX_I= 1000 ;
const int MAX_N= MAX_I* 7 ;
const int MAX_M= MAX_N<< 1 ;
int head[ MAX_N] , e_cnt, N, cnt= 0 ; ;
double d[ MAX_N] ;
struct node{
double x, y;
} seg[ MAX_I] [ 6 ] ;
struct node_p{
double x, y;
int id;
int bel;
} pos[ MAX_N] ;
double dis_ ( node_p a, node_p b) {
return sqrt ( ( a. x- b. x) * ( a. x- b. x) + ( a. y- b. y) * ( a. y- b. y) ) ;
}
struct Edge{
int to, next;
double val;
} edge[ MAX_M] ;
void add_edge ( int u, int v, double dis) {
edge[ e_cnt] . to= v;
edge[ e_cnt] . val= dis;
edge[ e_cnt] . next= head[ u] ;
head[ u] = e_cnt++ ;
return ;
}
double fuck ( node_p a, node c, node_p b) {
double x1, y1, x2, y2;
x1= a. x- c. x;
y1= a. y- c. y;
x2= b. x- c. x;
y2= b. y- c. y;
return x1* y2- x2* y1;
}
bool is_inter ( node_p a, node_p b, node c, node d) {
if ( fuck ( a, c, b) * fuck ( a, d, b) < eps)
return 1 ;
return 0 ;
}
priority_queue< pa, vector< pa> , greater< pa> > Q;
void Dijkstra ( int s) {
int i, j, k;
for ( i= 0 ; i< cnt; i++ )
d[ i] = INF;
d[ s] = 0 ;
while ( ! Q. empty ( ) )
Q. pop ( ) ;
Q. push ( {
0 , s} ) ;
while ( ! Q. empty ( ) ) {
pa jie= Q. top ( ) ;
Q. pop ( ) ;
int v= jie. sec;
if ( d[ v] < jie. fir)
continue ;
for ( i= head[ v] ; ~ i; i= edge[ i] . next) {
if ( d[ edge[ i] . to] > d[ v] + edge[ i] . val) {
d[ edge[ i] . to] = d[ v] + edge[ i] . val;
Q. push ( {
d[ edge[ i] . to] , edge[ i] . to} ) ;
}
}
}
return ;
}
int main ( )
{
while ( ~ scf ( "%d" , & N) && N!= - 1 ) {
int i, j, k, g;
double x, y;
cnt= 0 ;
pos[ cnt] . x= 0 ;
pos[ cnt] . y= 5 ;
pos[ cnt] . bel= 0 ;
pos[ cnt] . id= cnt++ ;
for ( i= 1 ; i<= N; i++ ) {
scf ( "%lf" , & x) ;
seg[ i] [ 0 ] . x= x;
seg[ i] [ 0 ] . y= 0 ;
for ( j= 1 ; j<= 4 ; j++ ) {
scf ( "%lf" , & y) ;
seg[ i] [ j] . x= x;
seg[ i] [ j] . y= y;
pos[ cnt] . x= x;
pos[ cnt] . y= y;
pos[ cnt] . bel= i;
pos[ cnt] . id= cnt++ ;
}
seg[ i] [ 5 ] . x= x;
seg[ i] [ 5 ] . y= 10 ;
}
pos[ cnt] . x= 10 ;
pos[ cnt] . y= 5 ;
pos[ cnt] . bel= N+ 1 ;
pos[ cnt] . id= cnt++ ;
memset ( head, - 1 , sizeof ( head) ) ;
e_cnt= 0 ;
for ( i= 0 ; i< cnt- 1 ; i++ ) {
for ( j= i+ 1 ; j< cnt; j++ ) {
if ( pos[ i] . bel== pos[ j] . bel)
continue ;
double dis= dis_ ( pos[ i] , pos[ j] ) ;
if ( pos[ j] . bel- pos[ i] . bel== 1 ) {
add_edge ( pos[ i] . id, pos[ j] . id, dis) ;
add_edge ( pos[ j] . id, pos[ i] . id, dis) ;
continue ;
}
bool flag= 0 ;
for ( k= pos[ i] . bel+ 1 ; k< pos[ j] . bel; k++ )
for ( g= 0 ; g<= 4 ; g+ = 2 ) {
if ( is_inter ( pos[ i] , pos[ j] , seg[ k] [ g] , seg[ k] [ g+ 1 ] ) ) {
flag= 1 ;
break ;
}
}
if ( flag)
break ;
}
if ( ! flag) {
add_edge ( pos[ i] . id, pos[ j] . id, dis) ;
add_edge ( pos[ j] . id, pos[ i] . id, dis) ;
}
}
}
Dijkstra ( 0 ) ;
prf ( "%.2f\n" , d[ cnt- 1 ] ) ;
}
return 0 ;
}