Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 6340 | Accepted: 2545 |
Description
Input
Output
Sample Input
1 5 4 6 7 8 2 4 2 7 8 9 7 3 4.5 6 7 -1
Sample Output
10.00 10.06
这道题结合了计算几何和最短路,首先记录所有点,包括(0,5),(10,5)还有每个门的上下两个点。
由于题目已经告知点的输入顺序是x递增,x相同的情况下y递增。那么我们在建图时,只需要前面的点和后面的点连边即可,因为不可能往回走的。在枚举两点(x1,y1),(x2,y2)[注:x1<x2]加边时,我们考虑x1和x2之间是否有点(代表有门)。
如果没点,之间连一条边,权值就是欧几里得距离。
如果有点,我们4个点连着看,分别对应了3堵墙和2个门,我们要判断(x1,y1)和(x2,y2)的连线是否与墙相交,这里用计算几何中的叉积来判断,如果墙的两点在连线的同侧或者墙的1点在连线上,那么表示墙和连线不相交,如果x1和x2之间的所有墙都不与连线相交,则连一条边。
建完图之后,就是裸的最短路了,可以用dijkstra算法,但是这里我为了练习bellman-ford,所以用了这个算法。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #define eps 1e-6 #define Maxn 100 using namespace std; struct line{ int u,v; double w; line(){} line(int uu,int vv,double ww):u(uu),v(vv),w(ww){} }p[Maxn*Maxn]; double x[Maxn],y[Maxn],dist[Maxn]; const double inf=100000000; bool cross(int l,int r,double dx,double dy1,double dy2){ double x1=x[r]-x[l],y1=y[r]-y[l]; double x2=dx-x[l],y2=dy1-y[l]; double x3=dx-x[l],y3=dy2-y[l]; double t1=x1*y2-y1*x2,t2=x1*y3-y1*x3; if(abs(t1)<eps||abs(t2)<eps||t1*t2>0) return true; return false; } bool ok(int l,int r){ int i=l; for(;abs(x[i]-x[l])<eps;i++); while(abs(x[i]-x[r])>eps){ if(!(cross(l,r,x[i],0,y[i])&&cross(l,r,x[i],y[i+1],y[i+2]) &&cross(l,r,x[i],y[i+3],10))) return false; i+=4; } return true; } double dis(int i,int j){ return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); } void bellman(int u,int n,int m){ for(int i=0;i<n;i++) dist[i]=inf; dist[u]=0; bool flag=true; for(int i=1;i<n;i++){ flag=false; for(int j=0;j<m;j++) if(dist[p[j].u]+p[j].w<dist[p[j].v]){ dist[p[j].v]=dist[p[j].u]+p[j].w; flag=true; } } } int main() { int n; double m; x[0]=0,y[0]=5; while(scanf("%d",&n),n!=-1){ int tot=1; while(n--){ scanf("%lf",&m); for(int i=0;i<4;i++){ scanf("%lf",y+tot); x[tot++]=m; } } x[tot]=10,y[tot++]=5; int num=0; for(int i=0;i<tot;i++) for(int j=i+1;j<tot;j++){ if(abs(x[j]-x[i])>eps&&ok(i,j)) p[num++]=line(i,j,dis(i,j)); } bellman(0,tot,num); printf("%.2f\n",dist[tot-1]); } return 0; }