Car的旅行路线(Floyd+模拟)

题目地址

贼鸡儿猥琐的一道题

好在数据不毒瘤,而且Floyd就OK了。

这道题的难点在于 建图,也很考验模拟能力,需要十分的有耐心。

建图

题目中告诉了我们一个矩形的三个点

我们在平面直角坐标系中随便画出一个直角三角形,假设(x1,y1)是直角的这个点,(x4,y4)是我们要求的第四个点,那么:

\[x_4=x_2+x_3-x_1,y_4=y_2+y_3-y_1\]

(因为我画图太渣只好文字解说)

我们尝试在原直角三角形的基础上把整个矩形画出来,矩形的四个顶点分别平行于坐标轴做平行线,得到了一个平行于坐标轴的大矩形EFGH,发现这里面有一些全等三角形,你就能证明出上面的结论了。

Q: 我们怎么知道哪个点是直角点呢?

A: 利用勾股定理逆定理。

建图部分就这样解决了。

求解

暴力双精度小数Floyd。

Code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define N 507
using namespace std;
inline int read() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
int n,s,t,A,B,cnt;
int T[N];
double g[N][N];
struct Point {
    int x,y,c;  //c就是哪个城市 
}P[N];
inline int Dis(Point p1,Point p2) {
    return (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y);   //为了方便计算,这个是距离的平方 
}
void work() {
    cnt = 0;    //初始化
    s = read(), t = read(), A = read(), B = read();
    for(int i=1;i<=s;++i) {
        for(int j=1;j<=3;++j) {
            P[++cnt].x = read(), P[cnt].y = read(), P[cnt].c = i;
        }
        T[i] = read();
        int a = Dis(P[cnt-2],P[cnt-1]), b = Dis(P[cnt-2],P[cnt]), c = Dis(P[cnt-1],P[cnt]), x4, y4;
        int x1=P[cnt-2].x, x2=P[cnt-1].x, x3=P[cnt].x, y1=P[cnt-2].y, y2=P[cnt-1].y, y3=P[cnt].y;
        if(a+b == c) x4 = x2+x3-x1, y4 = y2+y3-y1;
        if(a+c == b) x4 = x1+x3-x2, y4 = y1+y3-y2;
        if(b+c == a) x4 = x1+x2-x3, y4 = y1+y2-y3;
        P[++cnt].x = x4, P[cnt].y = y4, P[cnt].c = i;
    }
    memset(g,0x3f,sizeof(g));
    for(int i=1;i<=4*s;++i) {
        for(int j=1;j<=4*s;++j) {
            if(i == j) continue;
            double dis = sqrt(Dis(P[i],P[j])), w = 0.0;
            if(P[i].c == P[j].c) {
                w = dis * (double)(T[P[i].c]);
            } else {
                w = dis * (double)(t);
            }
            g[i][j] = g[j][i] = w;
        }
    }
    for(int k=1;k<=4*s;++k) {
        for(int i=1;i<=4*s;++i) {
            for(int j=1;j<=4*s;++j) {
                g[i][j] = min(g[i][j], g[i][k]+g[k][j]);
            }
        }
    }
    double ans = 0x3f3f3f;
    for(int i=1;i<=4*s;++i) {
        for(int j=1;j<=4*s;++j) {
            if(P[i].c==A && P[j].c==B) {
                ans = min(ans, g[i][j]);
            }
        }
    }
    printf("%.1lf",ans);
}
int main()
{
    n = read();
    while(n--) {
        work();
    }
    return 0;
}

PS:这个人的题解质量越来越差了

转载于:https://www.cnblogs.com/BaseAI/p/11602338.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dijkstra算法和Floyd算法都是图论中的经典算法,用于解决最短路径问题。下面分别介绍它们的算法模拟过程和算法实现。 1. Dijkstra算法 Dijkstra算法是一种贪心算法,用于求有向图的单源最短路径。算法流程如下: (1)初始化:将起点s到各个顶点的距离dist[i]初始化为无穷大,将起点s到自身的距离dist[s]初始化为0; (2)遍历所有顶点:从未确定最短路径的顶点集合S中选取距离起点s最近的顶点u,确定它的最短路径,并将其加入已确定最短路径的顶点集合T中; (3)更新距离:以u为中间点,更新起点s到未确定最短路径的顶点v的距离dist[v]。如果新的路径比原路径短,则更新dist[v],否则不变; (4)重复步骤(2)和(3),直到所有顶点都已加入已确定最短路径的顶点集合T。 算法实现: 以下是Dijkstra算法的Python实现,其中graph表示有向图的邻接矩阵,start表示起点: ```python def dijkstra(graph, start): n = len(graph) dist = [float('inf')] * n # 初始化距离 dist[start] = 0 visited = set() # 已确定最短路径的顶点集合 while len(visited) < n: u = min((v for v in range(n) if v not in visited), key=lambda x: dist[x]) visited.add(u) for v in range(n): if graph[u][v] > 0 and v not in visited: new_dist = dist[u] + graph[u][v] if new_dist < dist[v]: dist[v] = new_dist return dist ``` 2. Floyd算法 Floyd算法是一种动态规划算法,用于求有向图的多源最短路径。算法流程如下: (1)初始化:将任意两个顶点之间的距离dist[i][j]初始化为它们之间的边的权值,如果不存在边,则初始化为无穷大; (2)遍历所有顶点:对于每个顶点k,遍历所有顶点i和j,如果从i到j的路径经过顶点k比不经过顶点k的路径更短,则更新dist[i][j]; (3)重复步骤(2),直到所有顶点都已经遍历过。 算法实现: 以下是Floyd算法的Python实现,其中graph表示有向图的邻接矩阵: ```python def floyd(graph): n = len(graph) dist = [[graph[i][j] for j in range(n)] for i in range(n)] for k in range(n): for i in range(n): for j in range(n): if dist[i][k] != float('inf') and dist[k][j] != float('inf') and dist[i][k] + dist[k][j] < dist[i][j]: dist[i][j] = dist[i][k] + dist[k][j] return dist ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值