题目描述
在一个长宽均为10,入口出口分别为(0,5)、(10,5)的房间里,有几堵墙,每堵墙上有两个缺口,求入口到出口的最短路经。
输入格式
第一排为n(n<=20),墙的数目。
接下来n排,每排5个实数x,a1,b1,a2,b2。
x表示墙的横坐标(所有墙都是竖直的),a1-b1和a2-b2之间为空缺。
a1、b1、a2、b2保持递增,x1-xn也是递增的。
输出格式
输出最短距离,保留2位小数。
样例数据
样例输入
2
4 2 7 8 9
7 3 4.5 6 7
样例输出
10.06
题目分析
比较难建图的一道题
先把所有墙建成线段,将墙的两端作为结点建图,在图中所有结点间建边(但是边不能与墙相交),边权为欧几里德距离
然后跑一次dijkstra就可以了
代码写的有点智障
源代码
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
struct Point {
double x,y;
};
double Dist(Point a,Point b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
struct Vector {
double x,y;
};
Vector operator - (Point a,Point b) {
Vector c;
c.x=b.x-a.x;
c.y=b.y-a.y;
return c;
}
double Cross(Vector a,Vector b) { //叉积
return a.x*b.y-b.x*a.y;
}
bool Segment_Intersect(Point A,Point B,Point C,Point D) { //判断两线段是否相交
return (Cross((C-A),(D-A))*Cross((C-B),(D-B))<0)&&(Cross((A-C),(B-C))*Cross((A-D),(B-D))<0);
}
///
const int maxn=20005; //数组范围
struct Edge { //前向星
int from,to;
double dist;
};
struct HeapNode {
double d;
int u; //u为当前结点
bool operator < (HeapNode a) const {
return d>a.d;
}
};
struct Dijkstra {
int n,m;
vector<Edge> edges; //邻接表
vector<int> G[maxn]; //记录每个结点可以到达的结点
bool vst[maxn];
double dist[maxn];
int path[maxn]; //使用path记录最短路
void init(int n) {
this->n=n;
for(int i=1; i<=n; i++)G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,double dist) {
edges.push_back((Edge) {
from,to,dist
});
m=edges.size();
G[from].push_back(m-1);
}
void main(int s) { //核心算法
priority_queue<HeapNode> Q;
for(int i=1; i<=n; i++)dist[i]=1e10;
dist[s]=0;
path[s]=s;
memset(vst,0,sizeof(vst));
Q.push((HeapNode) {
0,s
});
while(!Q.empty()) {
HeapNode Now=Q.top();
Q.pop();
if(vst[Now.u])continue;
vst[Now.u]=1;
for(int i=0; i<G[Now.u].size(); i++) {
Edge& e=edges[G[Now.u][i]]; //边的信息
int Next=e.to;
if(dist[Next]>dist[Now.u]+e.dist) {
dist[Next]=dist[Now.u]+e.dist;
path[Next]=Now.u;
Q.push((HeapNode) {
dist[Next],Next
});
}
}
}
}
} ;
///
Point Start[105],End[105],P[105]; //障碍
Dijkstra dij;
int n,cnt=0,cnt1=0;
int main() {
scanf("%d",&n);
P[++cnt1]=(Point) {
0,5
};
P[++cnt1]=(Point) {
10,5
};
for(int i=1; i<=n; i++) {
double x,a1,b1,a2,b2;
scanf("%lf%lf%lf%lf%lf",&x,&a1,&b1,&a2,&b2);
Start[++cnt].x=x;
Start[cnt].y=0;
End[cnt].x=x;
End[cnt].y=a1;
Start[++cnt].x=x;
Start[cnt].y=b1;
End[cnt].x=x;
End[cnt].y=a2;
Start[++cnt].x=x;
Start[cnt].y=b2;
End[cnt].x=x;
End[cnt].y=10;
P[++cnt1]= (Point) {
x,a1
};
P[++cnt1]= (Point) {
x,b1
};
P[++cnt1]= (Point) {
x,a2
};
P[++cnt1]= (Point) {
x,b2
};
}
dij.init(cnt1);
for(int i=1; i<=cnt1; i++)
for(int j=i+1; j<=cnt1; j++) {
int bj=1;
for(int k=1; k<=cnt; k++)
if(Segment_Intersect(P[i],P[j],Start[k],End[k])) {
bj=0;
break;
}
if(bj==0)continue;
dij.AddEdge(i,j,Dist(P[i],P[j]));
dij.AddEdge(j,i,Dist(P[i],P[j]));
}
dij.main(1);
printf("%0.2lf\n",dij.dist[2]);
return 0;
}