这是一道紫题,然而实际上我觉得也就蓝题难度甚至不到。
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[5]; }w[30]; bool check(int a,int b,int na,int nb) { if(b - a <= 1) return 1; 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 + 1;i < b;i++) { double y = w[i].x * k + bb; if(y < w[i].y[1] || (y > w[i].y[2] && y < w[i].y[3]) || y > w[i].y[4]) return 0;//判断是否被墙挡住 } return 1; } void add(int a,int b,int na,int nb) { if(!check(a,b,na,nb)) return; dis[4 * a + na][4 * b + nb] = dis[4 * b + nb][4 * 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 = 0;i <= N;i++) { for(int j = 0;j <= N;j++) { if(i != j) dis[i][j] = 1e8; else dis[i][j] = 0; } } } void floyd() { for(int k = 1;k <= 4 * s + 4;k++) { for(int i = 1;i <= 4 * s + 4;i++) { for(int j = 1;j <= 4 * s + 4;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 = 1;i <= s;i++) { scanf("%lf %lf %lf %lf %lf",&w[i].x,&w[i].y[1],&w[i].y[2],&w[i].y[3],&w[i].y[4]); } w[0].x = 0;w[++s].x = 10; for(int i = 1;i <= 4;i++) w[0].y[i] = w[s].y[i] = 5; for(int a = 0;a < s;a++) { for(int b = a + 1;b <= s;b++) { for(int na = 1;na <= 4;na++) { for(int nb = 1;nb <= 4;nb++) { if(a == b) continue; add(a,b,na,nb); } } } } floyd(); printf("%.2lf",dis[1][4 * s + 1]); }