zoukankan      html  css  js  c++  java
  • UPC-9519 New Game(最短路)

    题目描述
    Eagle Jump公司正在开发一款新的游戏。泷本一二三作为其员工,获得了提前试玩的机会。现在她正在试图通过一个迷宫。

    这个迷宫有一些特点。为了方便描述,我们对这个迷宫建立平面直角坐标系。迷宫中有两条平行直线 L1:Ax+By+C1=0,L2:Ax+By+C2=0,还有 n 个圆 。角色在直线上、圆上、圆内行走不消耗体力。在其他位置上由S点走到T点消耗的体力为S和T的欧几里得距离。

    泷本一二三想从L1出发,走到L2。请计算最少需要多少体力。

    输入
    第一行五个正整数n,A,B,C1,C2(1≤n≤1000,−10000≤A,B,C1,C2≤10000),其中A,B 不同时为 0。
    接下来 n 行每行三个整数x,y,r(−10000≤x,y≤10000,1≤r≤10000) 表示一个圆心为 (x,y),半径为 r 的圆。

    输出
    仅一行一个实数表示答案。与标准答案的绝对误差或者相对误差不超过10-4即算正确。

    样例输入
    2 0 1 0 -4
    0 1 1
    1 3 1

    样例输出
    0.236068

    题解: 这题很像之前一道最短路的题,关于宇宙射线的,具体可以看https://blog.csdn.net/kuronekonano/article/details/80518997

    在这道题中,把收到最短时间宇宙射线换成了最小精力花费。
    实际上可以把起点和终点两条平行直线看做一个点,每个圆也看做一个点,然后建边,边权即距离,所有圆到起点和终点都有一条边,边权为圆心到直线的距离减去半径,圆与圆之间的边权(相离)圆心两点之间距离减去两圆半径,最后注意起点和终点存在一条边,边权为两平行直线间的距离。

    然后要说明一点是,之前一直以为题意是可以在园内走,其实是不行的,只能在圆的边上上走,也就是说,在圆之间移动时,相交和相离是可以直接用上述方法计算的,相交切直接边权为0,但是内含就会出现问题:
    在这里插入图片描述
    要用两圆半径之差的绝对值减去两圆心距离得到要走到路径。

    最后建完图直接跑一个最短路即可。
    注意起点和终点注意判断圆是否与直线相交相切。相交相切边权为0

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e3+10;
    double dist[maxn],mp[maxn][maxn];
    bool vis[maxn];
    int n;
    void SPFA(int s)
    {
        queue<int>q;
        while(!q.empty())q.pop();
        for(int i=0; i<=n; i++)dist[i]=1e14;
        memset(vis,false,sizeof vis);
        dist[s]=0;
        vis[s]=true;
        q.push(s);
        while(!q.empty())
        {
            int top=q.front();
            q.pop();
            vis[top]=false;
            for(int i=1; i<=n; i++)
            {
                if(dist[i]>dist[top]+mp[top][i])
                {
                    dist[i]=dist[top]+mp[top][i];
                    if(!vis[i])
                    {
                        vis[i]=true;
                        q.push(i);
                    }
                }
            }
        }
    }
    double cal(double x1,double y1,double x2,double y2)
    {
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    double line(double a,double b,double c,double x,double y)
    {
        return fabs(a*x+b*y+c)/sqrt(a*a+b*b);
    }
    double x[maxn],y[maxn],r[maxn];
    int main()
    {
        double a,b,c1,c2;
        while(scanf("%d%lf%lf%lf%lf",&n,&a,&b,&c1,&c2)!=EOF)
        {
            n+=2;
            r[1]=r[2]=0;
            mp[2][1]=mp[1][2]=fabs(c1-c2)/sqrt(a*a+b*b);
            for(int i=3; i<=n; i++)
            {
                scanf("%lf%lf%lf",&x[i],&y[i],&r[i]);
                mp[1][i]=mp[i][1]=line(a,b,c1,x[i],y[i]);
                if(r[i]>=mp[1][i])mp[1][i]=mp[i][1]=0;
                else mp[1][i]=mp[i][1]=mp[1][i]-r[i];
                mp[i][2]=mp[2][i]=line(a,b,c2,x[i],y[i]);
                if(r[i]>=mp[2][i])mp[2][i]=mp[i][2]=0;
                else mp[2][i]=mp[i][2]=mp[2][i]-r[i];
                for(int j=3; j<i; j++)
                {
                    double tmp=cal(x[i],y[i],x[j],y[j]);
                    if(r[i]+r[j]>=tmp)
                    {
                        if(fabs(r[i]-r[j])>tmp) mp[i][j]=mp[j][i]=fabs(r[i]-r[j])-tmp;
                        else mp[j][i]=mp[i][j]=0;
                    }
                    else mp[i][j]=mp[j][i]=tmp-r[i]-r[j];
                }
            }
            SPFA(1);
            printf("%f
    ",dist[2]);
        }
    }
    
    
  • 相关阅读:
    图01--[基本概念&&图的实现]
    并查集01--[Quick Find&&Quick Union]
    排序05--[计数排序&&基数排序&&桶排序]
    排序04--[快速排序&&希尔排序]
    harukaの赛前日常
    harukaの收藏夹
    hello world&Restart the Journey
    成外集训小记
    CSPS2019游记
    博弈论初步
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11135684.html
Copyright © 2011-2022 走看看