#floyd,斜率#洛谷 1354 房间最短路问题
题目
在一个长宽均为10,入口出口分别为(0,5),(10,5)的房间里有几堵墙,
每堵墙上有两个缺口,求入口到出口的最短路径。
分析
暴力建图,判断两个点是否有墙堵住,
可以求斜率然后判断所交点不能在墙上
在这里,你甚至可以用floyd求单源最短路
代码
#include <cstdio>
#include <cmath>
#include <map>
#define rr register
#define o(x) ((x)*(x))
using namespace std;
typedef double db; typedef pair<db,db> pdd;
const pdd St=make_pair(0.0,5.0),Ed=make_pair(10.0,5.0);
struct five{db x,y[4];}a[21]; db dis[83][83];
int n,st,ed,CNT; map<pdd,int>uk;
inline void Min(db &x,db y){x=x<y?x:y;}
inline bool against(db Xx,db Xy,db Yx,db Yy,int pl,int pr){
rr db K=(Yy-Xy)/(Yx-Xx),B=Xy-K*Xx;
for (rr int i=pl;i<=pr;++i){
rr db YY=K*a[i].x+B;
if (YY<a[i].y[0]||(a[i].y[1]<YY&&YY<a[i].y[2])||a[i].y[3]<YY) return 1;
}
return 0;
}
inline void Check(db Xx,db Xy,db Yx,db Yy,int pl,int pr){
if (against(Xx,Xy,Yx,Yy,pl,pr)) return;
rr pdd t1=make_pair(Xx,Xy),t2=make_pair(Yx,Yy);
if (!uk[t1]) uk[t1]=++CNT; if (t1==St) st=uk[t1];
if (!uk[t2]) uk[t2]=++CNT; if (t2==Ed) ed=uk[t2];
dis[uk[t1]][uk[t2]]=dis[uk[t2]][uk[t1]]=sqrt(o(Yx-Xx)+o(Yy-Xy));
}
signed main(){
scanf("%d",&n);
for (rr int i=1;i<83;++i)
for (rr int j=1;j<83;++j)
if (i!=j) dis[i][j]=1e9;
for (rr int i=1;i<=n;++i)
scanf("%lf%lf%lf%lf%lf",&a[i].x,&a[i].y[0],&a[i].y[1],&a[i].y[2],&a[i].y[3]);
Check(0.0,5.0,10.0,5.0,1,n);
for (rr int i=1;i<=n;++i)
for (rr int j=0;j<4;++j)
Check(0.0,5.0,a[i].x,a[i].y[j],1,i-1),
Check(a[i].x,a[i].y[j],10.0,5.0,i+1,n);
for (rr int i=1;i<n;++i) for (rr int i1=0;i1<4;++i1)
for (rr int j=i+1;j<=n;++j) for (rr int j1=0;j1<4;++j1)
Check(a[i].x,a[i].y[i1],a[j].x,a[j].y[j1],i+1,j-1);
for (rr int k=1;k<=CNT;++k)
for (rr int i=1;i<=CNT;++i)
for (rr int j=1;j<=CNT;++j)
if (k!=i&&k!=j&&i!=j)
Min(dis[i][j],dis[i][k]+dis[k][j]);
return !printf("%.2lf",dis[st][ed]);
}