题意:
在一个左下角坐标为(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;
}