这是一道紫题,然而实际上我觉得也就蓝题难度甚至不到。
and,这道题就是一道数学题,代码模拟计算过程。
求最短路嘛,肯定要考虑建图,只需要把中间的墙上每个口的边缘处的点作为图中的点就行。至于为什么,显然如果我们取中间任何一个点连边,到下一面墙时路径之和总是比连其中一个边缘的点要大,直观感(gán觉(juě)一下就行。连边我们一定会遇到一个问题,就是会被墙挡住。解决办法就是一次函数。我们求出要连这条边的直线解析式(直接模拟计算过程就行),然后求出在中间的墙上的函数值,如果这个函数值正好在缺口处就可以,否则被墙挡住,中间有多面墙枚举就行。
当我们建完图后这题就是最短路板子题了。n<=20,直接Floyd就水过去了。
据说lbg直接用dfs暴力水过去了,tql!
参考代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 100
using namespace std;
int s;
double dis[N][N];
struct wall
{
double x;
double y[];
}w[];
bool check(int a,int b,int na,int nb)
{
if(b - a <= ) return ;
double ya = w[a].y[na],yb = w[b].y[nb],xa = w[a].x,xb = w[b].x;
double k = (ya - yb) / (xa - xb);
double bb = ya - k * xa;//模拟待定系数法
for(int i = a + ;i < b;i++)
{
double y = w[i].x * k + bb;
if(y < w[i].y[] || (y > w[i].y[] && y < w[i].y[]) || y > w[i].y[]) return ;//判断是否被墙挡住
}
return ;
}
void add(int a,int b,int na,int nb)
{
if(!check(a,b,na,nb)) return;
dis[ * a + na][ * b + nb] = dis[ * b + nb][ * a + na] = sqrt((w[a].x - w[b].x) * (w[a].x - w[b].x) + (w[a].y[na] - w[b].y[nb]) * (w[a].y[na] - w[b].y[nb]));//连边,边权为两点间距离
}
void reset()
{
for(int i = ;i <= N;i++)
{
for(int j = ;j <= N;j++)
{
if(i != j) dis[i][j] = 1e8;
else dis[i][j] = ;
}
}
}
void floyd()
{
for(int k = ;k <= * s + ;k++)
{
for(int i = ;i <= * s + ;i++)
{
for(int j = ;j <= * s + ;j++)
{
dis[j][i] = dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
}
}
}
return;
}
int main()
{
reset();
scanf("%d",&s);
for(int i = ;i <= s;i++)
{
scanf("%lf %lf %lf %lf %lf",&w[i].x,&w[i].y[],&w[i].y[],&w[i].y[],&w[i].y[]);
}
w[].x = ;w[++s].x = ;
for(int i = ;i <= ;i++) w[].y[i] = w[s].y[i] = ;
for(int a = ;a < s;a++)
{
for(int b = a + ;b <= s;b++)
{
for(int na = ;na <= ;na++)
{
for(int nb = ;nb <= ;nb++)
{
if(a == b) continue;
add(a,b,na,nb);
}
}
}
}
floyd();
printf("%.2lf",dis[][ * s + ]); }