POJ 1556 计算几何 判断线段相交 最短路
题意:
在一个左下角坐标为(0,0),右上角坐标为(10,10)的矩形内,起点为(0,5),终点为(10,5),中间会有许多扇垂直于x轴的门,求从起点到终点在能走的情况下的最短距离。
分析:
既然是求最短距离,很容易想到最短距离的算法。那么接下来就是构造图了,门的两端点为图中的一个结点(不包括边界点),总共有4*n+2个结点。
枚举每一对结点连线,如果经过任意一张门,设距离为INF;否则距离就是它们的直线距离。
数据量不大,直接FLoyd。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define eps 1e-8 #define INF 1e9 using namespace std; const int maxn=1000+5; double g[maxn][maxn]; int n; typedef struct Point { double x,y; Point() {}; Point(double xx,double yy) { x=xx; y=yy; } } Vector; Point pot[maxn]; double crs_prdct(Vector a,Vector b) { return a.x*b.y-b.x*a.y; } double get_distance(Point a,Point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } Vector operator - (Point a,Point b) { return Vector(a.x-b.x,a.y-b.y); } bool intersect(Point p1,Point p2,Point q1,Point q2) { double crsp1=crs_prdct(q1-p1,q2-p1); double crsp2=crs_prdct(q1-p2,q2-p2); if(fabs(crsp1)<eps || fabs(crsp2)<eps) return true; return crsp1*crsp2<0? true:false; } int main() { // freopen("in.txt","r",stdin); pot[0]=Point(0,5); while(scanf("%d",&n) && n!=-1) { double x,y1,y2,y3,y4; for(int i=0; i<n; i++) { scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4); pot[4*i+1]=Point(x,y1); pot[4*i+2]=Point(x,y2); pot[4*i+3]=Point(x,y3); pot[4*i+4]=Point(x,y4); } pot[4*n+1]=Point(10,5); memset(g,0,sizeof(g)); for(int i=0; i<4*n+2; i++) { for(int j=i+1; j<4*n+2; j++) { int l=(i-1)/4,r=(j-1)/4; if(i==0) l=-1; bool flag=true; for(int k=l+1; k<r; k++) { if(intersect(Point(pot[4*k+1].x,0),pot[4*k+1],pot[i],pot[j])) { flag=false; break; } if(intersect(pot[4*k+2],pot[4*k+3],pot[i],pot[j])) { flag=false; break; } if(intersect(pot[4*k+4],Point(pot[4*k+4].x,10),pot[i],pot[j])) { flag=false; break; } } g[i][j]=g[j][i]=(flag? get_distance(pot[i],pot[j]):INF); } } for(int k=0;k<4*n+2;k++) for(int i=0;i<4*n+2;i++) for(int j=0;j<4*n+2;j++) g[i][j]=min(g[i][j],g[i][k]+g[k][j]); printf("%.2f\n",g[0][4*n+1]); } return 0; }