poj 3521 Geometric Map

来源:互联网 发布:电子驱鼠器软件 编辑:程序博客网 时间:2024/05/19 23:15

题目:给你平面上的n条线段,这些线段分成两类:

            1.街道边,两个端点都与其他线段相连,是可以行走的路径;

            2.标记边,只有一个端点和其他线段相连,标记路径的方向(角度大于90方向的可以通行)。

            计算起点到终点的最短距离。输出路径上的点,用0结束;如果不存在输出-1。

分析:计算几何、最短路。预处理有点麻烦的题目。由于分割街道的都是线段的端点,所以也并不是很纠结。

            首先,把边分成两种:街道边和标记边;

            然后,利用街道把街道截成不同的小街道,利用标记边判断小街道的方向;构造抽象的图、;

            最后,在抽象的图上计算最短路,输出结果即可。

注意:库函数sort在<algorithm>。

#include <algorithm>#include <iostream>#include <cstdlib>#include <cstdio>#include <cmath>using namespace std;//点结构 typedef struct pnode{int x,y;pnode( int a, int b ){x = a;y = b;}pnode(){}}point;point s,g,O,SAVE[205];//线段结构 typedef struct snode{point s,t;snode( point a, point b ){s = a;t = b;}snode(){}}segment;segment S[205],L[205],A[205];segment T[1205];//两点间距离 double dist( point a, point b ){return sqrt(0.0+(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); }//点乘判断角度   int angle( point a, point b, point c, point d )  {      return ((b.x-a.x)*(d.x-c.x)+(b.y-a.y)*(d.y-c.y));  }//点在线段上   bool p_on_s( point p, segment l )  {     if ( (l.t.x-l.s.x)*(p.y-l.s.y)-(l.t.y-l.s.y)*(p.x-l.s.x) == 0 )      if ( (p.x-l.s.x)*(p.x-l.t.x) <= 0 && (p.y-l.s.y)*(p.y-l.t.y) <= 0 )          return true;      return false;  }int   MAP[1005][1005];//存储坐标点的编号 point place[405];//储存对应编号点的坐标 //临接表 typedef struct enode{int    point;double length;enode* next;}edge;edge *H[405],E[1205];int   E_count;//初始化 void initial( int n ){for ( int i = 1 ; i <= n ; ++ i )H[i] = NULL;E_count =0;} //添加边 void addedge( int a, int b, double d ){E[E_count].point = b;E[E_count].length = d;E[E_count].next = H[a];H[a] = &E[E_count ++];}//临接表 end//spfa int stack[400];int visit[400];int father[400];double path[400];//递归,逆向输出路径上的点 void output( int s, int e ){if ( s != e ) output( s, father[e] );printf("%d %d\n",place[e].x,place[e].y);}//spfa计算最短路,存储父节点 void spfa( int s, int e, int n ){for ( int i = 1 ; i <= n ; ++ i ) {visit[i] = false;path[i] = 1e20;}path[s] = 0;stack[0] = s;visit[s] = true;int top = 1;while ( top ) {int now = stack[-- top];for ( edge* p = H[now] ; p ; p = p->next )if ( path[p->point] > path[now] + p->length ) {path[p->point] = path[now] + p->length;father[p->point] = now;if ( !visit[p->point] ) {visit[p->point] = true;stack[top ++] = p->point;}}visit[now] = false;}if ( path[e] != 1e20 ) {output( s, e );printf("0\n");}else printf("-1\n");}//spfa end//距离判断 bool cmp( point a, point b ){return dist( a, O ) < dist( b, O );}int main(){int n;while( ~scanf("%d",&n) && n ) {scanf("%d%d%d%d",&s.x,&s.y,&g.x,&g.y);for ( int i = 0 ; i < n ; ++ i )scanf("%d%d%d%d",&S[i].s.x,&S[i].s.y,&S[i].t.x,&S[i].t.y);//计算结点的编号和坐对应标 memset( MAP, 0, sizeof(MAP) );int number = 1;for ( int i = 0 ; i < n ; ++ i ) {if ( !MAP[S[i].s.x][S[i].s.y] ) {place[number] = S[i].s;MAP[S[i].s.x][S[i].s.y] = number ++;}if ( !MAP[S[i].t.x][S[i].t.y] ) {place[number] = S[i].t;MAP[S[i].t.x][S[i].t.y] = number ++;}}//把街道边和标记边分开int L_count = 0,A_count = 0;for ( int i = 0 ; i < n ; ++ i ) {bool flag1 = false,flag2 = false;for ( int j = 0 ; j < n ; ++ j ) {if ( i == j ) continue;if ( p_on_s( S[i].s, S[j] ) ) flag1 = true;if ( p_on_s( S[i].t, S[j] ) ) flag2 = true;}if ( flag1 && flag2 )L[L_count ++] = S[i];else A[A_count ++] = S[i];}//计算地图,把街道划分 int T_count = 0;for ( int i = 0 ; i < L_count ; ++ i ) {int count = 0;SAVE[count ++] = L[i].s;SAVE[count ++] = L[i].t;for ( int j = 0 ; j < L_count ; ++ j ) {if ( i == j ) continue;if ( p_on_s( L[j].s, L[i] ) ) SAVE[count ++] = L[j].s;if ( p_on_s( L[j].t, L[i] ) ) SAVE[count ++] = L[j].t;}//去掉重点 O = S[i].s;sort( SAVE, SAVE+count, cmp );int Count = 0;for ( int j = 1 ; j < count ; ++ j )if ( SAVE[Count].x != SAVE[j].x || SAVE[Count].y != SAVE[j].y )SAVE[++ Count] = SAVE[j];for ( int j = 0 ; j < Count ; ++ j )T[T_count ++] = segment( SAVE[j], SAVE[j+1] );}//构造抽象图,邻接矩阵 initial( number );for ( int i = 0 ; i < T_count ; ++ i ) {bool l_flag = true,r_flag = true;int  id1 = MAP[T[i].s.x][T[i].s.y];int  id2 = MAP[T[i].t.x][T[i].t.y];double dis = dist( T[i].s, T[i].t );for ( int j = 0 ; j < A_count ; ++ j ) {if ( p_on_s( A[j].s, T[i] ) ) {int ang = angle( T[i].s, T[i].t, A[j].s, A[j].t );if ( ang >= 0 ) l_flag = false;if ( ang <= 0 ) r_flag = false;}if ( p_on_s( A[j].t, T[i] ) ) {int ang = angle( T[i].s, T[i].t, A[j].t, A[j].s );if ( ang >= 0 ) l_flag = false;if ( ang <= 0 ) r_flag = false;}}//对应方向可以同行,添加对应的边 if ( l_flag ) addedge( id1, id2, dis );if ( r_flag ) addedge( id2, id1, dis );}//计算最短路 spfa( MAP[s.x][s.y], MAP[g.x][g.y], number );}return 0;}