CODEVS 1041Car的旅行路线

本文介绍了一种基于FLOYD算法解决城市间多个飞机场之间的最短路径问题的方法。通过计算城市内各飞机场间的距离及城市间飞机场的距离,实现了A到B所有可能路径中最短路径的最小值计算。

声明:源代码从iwtwiioi_2处转载,这是 原文链接 。我在此代码的基础上做进一步的说明解释。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <iomanip>
#include <cmath>
using namespace std;
const double oo = 10000000;
//城市的飞机场 (x-1)*4+1代表第x个城市开始的飞机场下标
#define CTOA(x) (((x-1)<<2)+1)
//距离
#define DISTANCE(x1,y1,x2,y2) ((double)sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)))
//此题我用FLOYD做的,因为数据太弱,过了
//每个飞机场为一个节点,答案就是A到B所有的路线最短路的最小值
struct city
{
    int x[4], y[4];
}ct[105];

double node[4050][4050];
double T;
int s, t, A, B, N, i, j, k, l, temp, airport, tx[3], ty[3];
//至于计算第四个点,由数学知识我们可以知道,相互垂直的两条直线的斜率互为负倒数,所以我们只要每次计算AB、BC的斜率。
//如果不满足条件,那么将A、B、C的坐标分别赋值为B、C、A,这样不断迭代,直到AB、BC垂直,这样就能计算出第四个点的坐标。
//还要注意一个问题,如果AB或者BC与坐标轴垂直,需要单独讨论这种情况,因为被除数不能为零。
//(1) 首先判断直角的位置:
//因为从测试数据文件中读入的三个点的坐标是无序的,因此需判断直角的位置,然后在计算第四个点的坐标。
//对于线段L1、L2,如果(x1-x2)*(x3-x2)+(y1-y2)*(y3-y2)=0,那么L1 ⊥ L2。
//(2) 计算(x4,y4):
//由x4-x3=x1-x2得x4=x1-x2+x3,同样的y4=y1-y2+y3
void getfour(int c) //获取第四个城市
{
    memcpy(tx, ct[c].x, sizeof(tx));
    memcpy(ty, ct[c].y, sizeof(ty));
    int tt;
    while((tx[0]-tx[1])*(tx[2]-tx[1])+(ty[0]-ty[1])*(ty[2]-ty[1]))
    {
        tt = tx[0]; tx[0]=tx[1]; tx[1]=tx[2]; tx[2]=tt;
        tt = ty[0]; ty[0]=ty[1]; ty[1]=ty[2]; ty[2]=tt;
    }
    ct[c].x[3] = tx[0]-tx[1]+tx[2];
    ct[c].y[3] = ty[0]-ty[1]+ty[2];}

int main()
{
    cin >> N;
    while(N--)
    {
        cin >> s >> t >> A >> B;
        //注意A=B的情况,也就是出发的城市就是结束的城市,这是要直接输出‘0.0’;
        if(A == B) {cout << "0.0\n";continue;}
        //s<<2表示飞机场数量,即s*4
        airport = s << 2;
        for(i = 1; i <= airport; i++)
            for(j = 1; j <= airport; j++)
                node[i][j] = oo; //初始化

        for(i = 1; i <= s; i++)
        {
            for(j = 0; j < 3; j++)
                cin >> ct[i].x[j] >> ct[i].y[j];
            cin >> T;
            getfour(i);
            //初始同一城市飞机场的花费
            for(j = 0; j < 4; j++)
                for(k = 0; k < 4; k++)
                    if(j != k)
                        node[CTOA(i)+j][CTOA(i)+k] = DISTANCE(ct[i].x[j], ct[i].y[j], ct[i].x[k], ct[i].y[k]) * T;
        }

        //初始不同城市飞机场的花费
        for(i = 1; i <= s; i++)
            for(j = 1; j <= s; j++)
                if(i != j)
                    for(k = 0; k < 4; k++)
                        for(l = 0; l < 4; l++)
                            node[CTOA(i)+k][CTOA(j)+l] = (DISTANCE(ct[i].x[k], ct[i].y[k], ct[j].x[l], ct[j].y[l]) * t);

        //Floyd
        for(k = 1; k <= airport; k++)
            for(i = 1; i <= airport; i++)
                for(j = 1; j <= airport; j++)
                    node[i][j] = min(node[i][j], node[i][k]+node[k][j]);

        //A到B所有的路线最短路的最小值
        double ans = oo;
        for(i = 0; i < 4; i++)
            for(j = 0; j < 4; j++)
                ans = min(ans, node[CTOA(A)+i][CTOA(B)+j]);
        printf("%.1lf",ans);
    }
    return 0;
}

题解:本题我一开始并未使用数组来储存每个城市的机场坐标。如下:

struct node{//不要这么做!!!
    int x1,y1;//不要这么做!!!
    int x2,y2;//不要这么做!!!
    int x3,y3;//不要这么做!!!
    int x4,y4;//不要这么做!!!
    int train;//不要这么做!!!
}city[110];//不要这么做!!!

导致后面的程序冗长、复杂,然后。。。我就不想写了。。。所以我copy了iwtwiioi_2 的代码,在这里表示感谢!
注意:一定要使用数组来储存机场的坐标!就像iwtwiioi_2 这样:

struct city{//应该这样做!!!
    int x[4], y[4];//应该这样做!!!
}ct[105];//应该这样做!!!

对于第四个点的求解,除了源代码的注释上的方法外还可以从向量的方面理解。首先也要讨论哪个点是直角点,而直角点无非是(x1,y1),(x2,y2),(x3,y3)中的一个,所以讨论三次。根据向量的点积的定义,假设有三个点A(x1,y1),B(x2,y2),C(x3,y3),若AB⊥BC,则B为直角点,坐标间关系满足(点乘): ( x1-x2 , y1-y2 ) • ( x3-x2 , y3-y2 ) =0 => (x1-x2) * (x3-x2) + (y1-y2) * (y3-y2)=0 。由此(x4,y4)点的坐标也可以轻松给出:x4=x1+x3-2 * x2 , y4=y1+y3-2 * y2。

乐播投屏是一款简单好用、功能强大的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各大卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强大:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值