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==-1break;
        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.0e10break;
            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;
}

 

相关文章: