[计算几何]POJ 1556 判断线段相交+Dijkstra

http://acm.pku.edu.cn/JudgeOnline/problem?id=1556

挺有意思的一个题。

[计算几何]POJ 1556 判断线段相交+Dijkstra 

题目大意如上图,有一个房间,要从(0,5)走到(10,5),房间内有一些竖直的墙壁,现在要求最短的路径长度。

首先,很直观很显然的,要使路径达到最短,我们每次都是沿着墙的端点按直线走,也就是从一个墙的端点走到另一个墙的端点,这样问题就可以转换为图论中的最短路问题了,设上图中有n个端点,这样可以建立一个n+2个点的有向带权图g,g[i][j]表示从端点i到端点j的长度。

下面是关于怎么构图:枚举2个端点i和j,如果线段Pi->Pj于横坐标处于Xi,Xj之间的墙壁都没有相交的话,则可以从端点i直线走到端点j,在图g中假如一条由i指向j的边,权值为distance(Pi,Pj)。

这样,最构造出来的图求最短路就可以得到最后问题的解了。

#include  < iostream >
#include 
< string >
#include 
< cstdio >
#include 
< cmath >
using   namespace  std;
#define  EPS 1.0e-6

struct  Point {
    
double  x,y;
};

int  dblcmp( double  r) {
    
if (fabs(r) < EPS)  return   0 ;
    
return  r > 0 ? 1 : - 1 ;
}

double  dot( double  x1, double  y1, double  x2, double  y2) {
    
return  x1 * y2 - x2 * y1;
}

double  cross(Point a,Point b,Point c) {
    
return  dot(b.x - a.x,b.y - a.y,c.x - a.x,c.y - a.y);
}
// 判断线段(a,b)和(c,d)是否相交(不算端点)
bool  lineseg(Point a,Point b,Point c,Point d) {
    
return  (((dblcmp(cross(a,b,c)) ^ dblcmp(cross(a,b,d))) ==- 2 )
                
&& ((dblcmp(cross(c,d,a)) ^ dblcmp(cross(c,d,b))) ==- 2 ));
}
double  mydist(Point a,Point b) {
    
return  sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

double  g[ 200 ][ 200 ];     // 图的临街矩阵
int  s,t;
int  n;
Point line[
200 ][ 2 ];     // 存储墙
Point pts[ 200 ];         // 存储墙2端的端点

int  main() {
    
double  x,y1,y2,y3,y4;
    
while (cin >> n) {
        
if (n ==- 1 break ;
        s
= 0 ,t = 4 * n + 1 ;
        pts[
0 ].x = 0 ;
        pts[
0 ].y = 5 ;
        pts[t].x
= 10 ;
        pts[t].y
= 5 ;

        
for ( int  i = 0 ;i < n;i ++ ) {
            cin
>> x >> y1 >> y2 >> y3 >> y4;
        
            line[i
* 3 ][ 0 ].x = x;
            line[i
* 3 ][ 0 ].y = 0 ;
            line[i
* 3 ][ 1 ].x = x;
            line[i
* 3 ][ 1 ].y = y1;

            line[i
* 3 + 1 ][ 0 ].x = x;
            line[i
* 3 + 1 ][ 0 ].y = y2;
            line[i
* 3 + 1 ][ 1 ].x = x;
            line[i
* 3 + 1 ][ 1 ].y = y3;

            line[i
* 3 + 2 ][ 0 ].x = x;
            line[i
* 3 + 2 ][ 0 ].y = y4;
            line[i
* 3 + 2 ][ 1 ].x = x;
            line[i
* 3 + 2 ][ 1 ].y = 10 ;

            pts[
4 * i + 1 ].x = x;
            pts[
4 * i + 1 ].y = y1;
            pts[
4 * i + 2 ].x = x;
            pts[
4 * i + 2 ].y = y2;
            pts[
4 * i + 3 ].x = x;
            pts[
4 * i + 3 ].y = y3;
            pts[
4 * i + 4 ].x = x;
            pts[
4 * i + 4 ].y = y4;
        }
        
for ( int  i = s;i <= t;i ++ )
            
for ( int  j = s;j <= t;j ++ )
                g[i][j]
= 1.0e10 ;
        
// 下面建图
         for ( int  i = 0 ;i <= t;i ++ ) {
            
for ( int  j = i + 1 ;j <= t;j ++ ) {
                
bool  ok = true ;
                
for ( int  k = 0 ;k < 3 * n;k ++ ) {
                    
if (pts[i].x != pts[j].x && pts[i].x != line[k][ 0 ].x && pts[j].x != line[k][ 0 ].x && lineseg(pts[i],pts[j],line[k][ 0 ],line[k][ 1 ])) {
                        ok
= false ;
                        
break ;
                    }
                }
                
if (ok) {
                    g[i][j]
= mydist(pts[i],pts[j]);
                }
            }
        }

        
// 下面用Dijkstra算法求最短路
         double  dist[ 200 ];
        
for ( int  i = s;i <= t;i ++ ) dist[i] = 1.0e10 ;
        dist[
0 ] = 0 ;
        
bool  vis[ 200 ];
        memset(vis,
false , sizeof (vis));
        
for ( int  i = s;i <= t;i ++ ) {
            
double  mind = 1.0e10 ;
            
int  id;
            
for ( int  j = s;j <= t;j ++ ) {
                
if ( ! vis[j] && mind > dist[j]) {
                    id
= j;
                    mind
= dist[j];
                }
            }
            
if (mind == 1.0e10 break ;
            vis[id]
= true ;
            
for ( int  j = s;j <= t;j ++ ) {
                
if ( ! vis[j] && dist[id] + g[id][j] < dist[j]) {
                    dist[j]
= dist[id] + g[id][j];
                }
            }
        }

        printf(
" %.2f\n " ,dist[t]);
    }
    
return   0 ;
}

 

你可能感兴趣的:(dijkstra)