题目大意:在一个正方形的小室中,有一些障碍墙(0到18个),每个障碍墙有两扇门允许通过,你的目标是找到起点( x=0,y=5 )到终点( x=10,y=5 )的最短路径。
分析:这是ljr《算法艺术与信息学竞赛》p.354的一道例题,书中给
出的解法是将这道题转化成图论中的最短路问题。将起点、终点以及所有门的两个边界点看做节点,两个点之间若可以直达,则在其所代表的的节点间加一条边(边权为点之间的距离)。
这道题我在网上居然没有找到题解。。只好自己做了,代码很丑,不过还好过了。
代码:
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <cmath>
#include <cstring>
using namespace std;
const double precision=1e-7;
const double INF=999999.0;
struct Wall{
double x;
double y[4];
};
struct Point{
Point(double _x,double _y){
x=_x;
y=_y;
}
double x,y;
};
Point start(0,5);
Point endp(10,5);
Wall wall[20];
double map[100][100];
double dist[100];
bool vis[100];
int n;
double dis(Point& a,Point& b){
double dx=b.x-a.x,dy=b.y-a.y;
return sqrt(dx*dx+dy*dy);
}
int dlbcmp(double x){
return fabs(x)<precision?0:(x>0?1:-1);
}
double det(double x1,double y1,double x2,double y2){
return x1*y2-x2*y1;
}
double cross(Point a,Point b,Point c){
return det(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y);
}
bool check(Point a,Point b,Point c,Point d){
return (dlbcmp(cross(a,b,c))^dlbcmp(cross(a,b,d)))==-2&&
(dlbcmp(cross(c,d,a))^dlbcmp(cross(c,d,b)))==-2;
}
void subBuild(Point p,int id,int j){
int i=(id-1)/4;
int k=id?i+1:0;
if(j==n){
for(;k<j;++k){
if( check(p,endp,Point(wall[k].x,0),Point(wall[k].x,wall[k].y[0]))||
check(p,endp,Point(wall[k].x,wall[k].y[1]),Point(wall[k].x,wall[k].y[2]))||
check(p,endp,Point(wall[k].x,wall[k].y[3]),Point(wall[k].x,10)))
break;
}
if(k==j) map[id][4*n+1]=dis(p,endp);
}
else{
int temp=k;
for(int t=0;t<4;++t){
Point node(wall[j].x,wall[j].y[t]);
for(k=temp;k<j;++k){
if( check(p,node,Point(wall[k].x,0),Point(wall[k].x,wall[k].y[0]))||
check(p,node,Point(wall[k].x,wall[k].y[1]),Point(wall[k].x,wall[k].y[2]))||
check(p,node,Point(wall[k].x,wall[k].y[3]),Point(wall[k].x,10)))
break;
}
if(k==j) map[id][4*j+1+t]=dis(p,node);
}
}
}
void build(){
int N=4*n+2;
for(int i=0;i<N;++i){
for(int j=0;j<N;++j){
map[i][j]=INF;
}
}
for(int i=0;i<=n;++i){
subBuild(start,0,i);
}
for(int i=0;i<n;++i){
for(int j=i+1;j<=n;++j){
for(int k=0;k<4;++k){
subBuild(Point(wall[i].x,wall[i].y[k]),4*i+1+k,j);
}
}
}
}
void solve(){
int N=4*n+2;
memset(vis,false,sizeof vis);
for(int i=1;i<N;++i){
dist[i]=map[0][i];
}
dist[0]=0;
for(int i=1;i<N;++i){
double min_dist=INF;
int p;
for(int j=1;j<N;++j){
if(dist[j]<min_dist&&(!vis[j])){
min_dist=dist[p=j];
}
}
vis[p]=true;
for(int i=1;i<N;++i){
if(!vis[i]){
dist[i]=min(dist[p]+map[p][i],dist[i]);
}
}
}
cout<<fixed<<setprecision(2)<<dist[N-1]<<endl;
}
int main(){
ios::sync_with_stdio(false);
while(cin>>n,n!=-1){
for(int i=0;i<n;++i){
cin>>wall[i].x;
for(int j=0;j<4;++j){
cin>>wall[i].y[j];
}
}
build();
solve();
}
return 0;
}