/* 返回顶部 */

P1354 房间最短路问题

传送门

可以发现,最短路一定要经过墙壁的断点。

那么把房间看作一个有向图,墙壁的断点为节点,求从起点到终点的最短路。

这道题的难点在于建图。枚举所有的断点,若可以走则加入这条边。

判断两点是否连通,即为判断两点之间是否有其他墙壁阻隔。

两点的连线可以看作一个一次函数$y=kx+B$,

$k=(x2-x1)/(y2-y1),B=y1-k*x1$

得到函数解析式后,算出中间的每一个墙壁与这条直线交点的$y$坐标,

由于给出墙壁的$x$是递增的,所以只需要枚举墙壁$x1+1$~$x2-1$。

若这个$y$恰好在墙壁的缺口里,则是连通的。

边的权值即为两点之间的欧几里德距离:$sqrt( (x2-x1)^2 + (y2-y1)^2 )$

边的序号:由于一条墙壁只有四个断点,则某个断点的序号可以记作$x*4+y[i]$,$i$为第几个断点。

数据范围很小,最后用floyd求出最短路即可。

注意开double!

代码如下

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define MogeKo qwq 
using namespace std;
const int maxn = 30;
const int INF = 2147483647;
int n;

double e[200][200];

struct wall {
    double x,y[5];
} w[maxn];

bool check(int a,int b,int g1,int g2) {
    if(b-a<2)return true;
    double xi = w[a].x,xii = w[b].x;
    double yi = w[a].y[g1],yii = w[b].y[g2];
    double k = (yii-yi)/(xii-xi);
    double B = yi-k*xi;
    for(int i = a+1; i <= b-1; i++) {
        double yy = k*w[i].x+B;
        if(!((yy>w[i].y[1]&&yy<w[i].y[2])||(yy>w[i].y[3]&&yy<w[i].y[4])))return false;
    }
    return true;
}

void add(int a,int b,int g1,int g2) {
    if(!check(a,b,g1,g2))return;
    double xi = w[a].x,xii = w[b].x;
    double yi = w[a].y[g1],yii = w[b].y[g2];
    e[(a<<2)+g1][(b<<2)+g2] = sqrt(pow(xii-xi,2)+pow(yii-yi,2));
}

void floyd() {
    for(int k = 1; k <= (n<<2)+4; k++)
        for(int i = 1; i <= (n<<2)+4; i++)
            for(int j = 1; j <= (n<<2)+4; j++)
                e[i][j] = min(e[i][j],e[i][k]+e[k][j]);
}

int main() {
    scanf("%d",&n);
    for(int i = 1; i <= n; i++) {
        scanf("%lf",&w[i].x);
        for(int j = 1; j <= 4; j++)
            scanf("%lf",&w[i].y[j]);
    }
    w[0].x = 0,w[++n].x = 10;
    for(int i = 1; i <= 4; i++)
        w[0].y[i] = w[n].y[i] = 5;
    for(int i = 1; i <= (n<<2)+4; i++)
        for(int j = 1; j <= (n<<2)+4; j++)
            e[i][j] = INF;
    for(int i = 0; i <= n; i++)
        for(int j = i+1; j <= n; j++)
            for(int k = 1; k <= 4; k++)
                for(int l = 1; l <= 4; l++)
                    add(i,j,k,l);
    floyd();
    printf("%.2lf",e[1][(n<<2)+1]);
    return 0;
}
View Code

 

 

posted @ 2019-04-17 18:02  Mogeko  阅读(455)  评论(0编辑  收藏  举报