这道题思路很简单,但是不知道为什么我实现的时候觉得极其恶心……于是憋了一天一夜,终于憋出来了,心情舒畅
题解:
很明显我们最后要跑的是最短路,所以现在的目标是构建一个无向\有向图(随意有无向)
图的构建:枚举起点 + 终点 + 题目给出的所有点 之间的任意两点间是否存在路径。枚举的时候还要判断这条边是否被堵。
最后就是跑一遍最短路
关于实现:
主要就是建图的问题。我为了方便自己理解分别弄了 一个door数组用来存所有的门 以及 一个point数组来存所有的点。
door数组的头和尾分别弄成x=0和x=10的整堵墙(即把(0,0)(0,10)当做一个门,(10,0)(10,10)也当做一个门,并且分别存两次(因为每一列正常有两道门))
在枚举的时候,从左至右枚举点,注意如果两点在同一列的时候就跳出,直接赋值为无穷。还有当起点为0的时候则无视刚刚那个规则。
上面还有一大堆模板。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include <cstring>
using namespace std;
#define infinity 1e20 //模板begin
#define EP 1e-10
const int Max = 50;
const int MAXV = 300 ;
const double PI = 2.0*asin(1.0); //高精度求PI
struct Lpoint
{
double x,y;
} point[Max<<2]; //点
struct Llineseg
{
Lpoint a,b;
} door[Max][2]; //线段
struct Ldir
{
double dx,dy;
}; //方向向量
struct Lline
{
Lpoint p;
Ldir dir;
}; //直线
struct Lrad
{
Lpoint Sp;
Ldir dir;
}; //射线
struct Lround
{
Lpoint co;
double r;
};//圆
double p2pdis(Lpoint p1,Lpoint p2)
{
return (sqrt((p1.x-p2.x) * (p1.x-p2.x) +
(p1.y-p2.y) * (p1.y-p2.y)));
}
double xmulti(Lpoint p1,Lpoint p2,Lpoint p0)
{
return((p1.x-p0.x) * (p2.y-p0.y) -
(p2.x-p0.x) * (p1.y-p0.y));
}
double mx(double t1,double t2)
{
if(t1>t2) return t1;
return t2;
}
double mn(double t1,double t2)
{
if(t1<t2) return t1;
return t2;
}
int lsinterls(Llineseg u,Llineseg v)
{
return( (mx(u.a.x,u.b.x)>=mn(v.a.x,v.b.x))&&
(mx(v.a.x,v.b.x)>=mn(u.a.x,u.b.x))&&
(mx(u.a.y,u.b.y)>=mn(v.a.y,v.b.y))&&
(mx(v.a.y,v.b.y)>=mn(u.a.y,u.b.y))&&
(xmulti(v.a,u.b,u.a)*xmulti(u.b,v.b,u.a)>=0)&&
(xmulti(u.a,v.b,v.a)*xmulti(v.b,u.b,v.a)>=0));
}
int ponls(Llineseg l,Lpoint p)
{
return( (xmulti(l.b,p,l.a)==0) &&
( ((p.x-l.a.x)*(p.x-l.b.x)<0 ) ||
((p.y-l.a.y)*(p.y-l.b.y)<0 )) );
}
int Euqal_Point(Lpoint p1,Lpoint p2)
{
return((fabs(p1.x-p2.x)<EP)&&(fabs(p1.y-p2.y)<EP));
}
int lsinterls_A(Llineseg u,Llineseg v)
{
return((lsinterls(u,v)) && (!Euqal_Point(u.a,v.a))&&
(!Euqal_Point(u.a,v.b)) &&
(!Euqal_Point(u.b,v.a))&&
(!Euqal_Point(u.b,v.b)));
}
//模板end
double Edge[Max<<2][Max<<2];
//Llineseg line[Max][Max<<2];
//int Num_line[Max];
void Make_line(int n)
{
// memset(Num_line, 0, sizeof(Num_line));
Llineseg tem;
for(int i=0; i<=n; i++)//begin point
{
for(int j=i; j<=n; j++)//end point
{
if(i!=0 && (i+3)/4 == (j+3)/4) //(x+3)/4 代表该点所的墙的列数 如输入数据为2,则这组数据一共有4列墙(+起点和终点)
{
Edge[i][j] = Edge[j][i] = 1e8;
continue;
}
tem.a = point[i];
tem.b = point[j];
int vis = 0;
for(int k=(i+3)/4; k<=(j+3)/4; k++)//blocks
{
for(int l=0; l<2 && k!=(j+3)/4; l++)
{
// if(lsinterls_A(tem,line[k][l]))
double tem_judge = xmulti(tem.a, tem.b, door[k][l].a) * xmulti(tem.a ,tem.b, door[k][l].b);
if(tem_judge < 0 || fabs(tem_judge) < 1e-6)
break;
else if(l==1)
{
vis = 1;
break;
}
}
if(vis) k = (j+3)/4;
if(k==(j+3)/4)
{
if(!vis)Edge[i][j] = Edge[j][i] = p2pdis(point[i], point[j]);
else
Edge[i][j] = Edge[j][i] = 1e8;
}
}
}
}
}
bool vis[Max<<2];
double dist[Max<<2];
void dijkstra(int num, int u0)
{
memset(vis, 0 ,sizeof(vis));
for(int i=0; i<=num; i++)
dist[i] = Edge[u0][i];
vis[u0] = true;
dist[u0] = 0;
for(int i=1; i<=num; i++)
{
int tem_min = 1e8;
for(int j=0; j<=num; j++)
{
if((u0!=0 && (u0-1)/4 == (j-1)/4) || u0 == j) continue;
if(!vis[j] && dist[j] < tem_min)
{
tem_min = dist[j];
u0 = i;
}
}
vis[u0] = true;
for(int j=0; j<=num; j++)
{
// if((u0!=0 && (u0-1)/4 == (j-1)/4) || u0 == j) continue;
if(!vis[j] && dist[u0] + Edge[u0][j] < dist[j])
dist[j] = Edge[u0][j] + dist[u0];
}
}
}
int main()
{
// freopen("1556.txt","r",stdin);
int n;
while(~scanf("%d",&n) && n!=-1)
{
memset(Edge, 0, sizeof(Edge));
for(int i=1; i<=n; i++)
{
double x;
scanf("%lf",&x);
scanf("%lf %lf %lf %lf",&door[i][0].a.y,
&door[i][0].b.y, &door[i][1].a.y,
&door[i][1].b.y);
door[i][0].a.x = door[i][0].b.x =
door[i][1].a.x = door[i][1].b.x = x;
point[4*(i-1)+1].y = door[i][0].a.y;
point[4*(i-1)+2].y = door[i][0].b.y;
point[4*(i-1)+3].y = door[i][1].a.y;
point[4*(i-1)+4].y = door[i][1].b.y;
point[4*(i-1)+1].x = point[4*(i-1)+2].x = point[4*(i-1)+3].x = point[4*(i-1)+4].x = x;
}
//起点终点开口初始化
door[0][0].a.x = door[0][0].a.y = 0;
door[0][0].b.x = 0;
door[0][0].b.y = 10;
door[0][1].a = door[0][0].a;
door[0][1].b = door[0][0].b;
door[n+1][0].a.x = 10;
door[n+1][0].a.y = 0;
door[n+1][0].a.x = 10;
door[n+1][0].a.y = 10;
door[n+1][1].a = door[n+1][0].a;
door[n+1][1].b = door[n+1][0].b;
point[0].x = 0;
point[0].y = 5;
point[4*n+1].x = 10;
point[4*n+1].y = 5;
Make_line(4*n+1);
dijkstra(4*n + 1, 0);
printf("%.2lf\n",dist[4*n + 1]);
}
return 0;
}