zoukankan      html  css  js  c++  java
  • 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

     

  • 相关阅读:
    回车与换行的区别
    C# 验证数字
    FCKeditor 2.6.6在ASP中的安装及配置方法分享--ZZ转载自网络
    关于Application.Lock…Application.Unlock有什么作用?
    关于Application.Lock和Lock(obj)
    C#解决Linq OrderBy() 失效的小技巧
    文件夹添加 IIS 应用程序池用户权限
    we7调用模板如何区分栏目页与详细页
    第二阶段冲刺(第十天)
    每周总结(第十六周)
  • 原文地址:https://www.cnblogs.com/mogeko/p/10725228.html
Copyright © 2011-2022 走看看