山东理工大学2020年全国天梯赛赛前个人专题强化赛---C(最短路)

本文介绍了如何解决山东理工大学2020年全国天梯赛中C题——最短路问题。分别探讨了使用Floyd算法和Dijkstra算法的思路,并提供了相关代码示例。Floyd算法虽然代码简洁,但在时间效率上可能不占优势。同时,文章以城市间紧急救援问题为例,阐述了该题目的实际应用和挑战,指出解决此类问题能带来更大的学习收获。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述
旅游规划这个题,其实用floyd也可以做,而且代码看起来更舒服,先给一个floyd的代码(非全原创,侵删),但要注意,由于floyd确实多算了很多无用的数据,如果卡你时间,floyd是过不了的。

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f

int node [505][505];
int dis[505][505];
int main()
{
    int n,m,s,d,i,j,k,x,y,q,w;
    cin>>n>>m>>s>>d;
    memset(dis,INF,sizeof(dis));
    memset(node,INF,sizeof(node));
    for(int i=0;i<n;i++)
    {
    dis[i][i]=0;
    node[i][i]=0;
    }
    for(i=0; i<m; i++)
    {
        scanf("%d %d %d %d",&x,&y,&q,&w);
        node[x][y] = node[y][x] = q;
        dis[x][y] = dis[y][x] = w;
    }
    for(k=0; k<n; k++)
    {
        for(i=0; i<n; i++)
        {
            for(j=0; j<n; j++)
            {
                if(node[i][j]>node[i][k]+node[k][j]||(node[i][j]==node[i][k]+node[k][j]&&dis[i][j]>dis[i][k]+dis[k][j]))
                {
                    node[i][j] = node[i][k]+node[k][j];
                    dis[i][j] = dis[i][k]+dis[k][j];
                }
            }
        }
    }
    printf("%d %d\n",node[s][d],dis[s][d]);
    return 0;
}

dijkstra算法(非全原创,侵删)

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f;
using namespace std;

int n,m,s,d;
int G[505][505];
int a[505][505];
int lowcost[505];
int fee[505];
int vis[505];
void dij()
{
    for(int i=0;i<n;i++)
    {
        lowcost[i]=INF;
    }
    lowcost[s]=0;
    for(int mm=0;mm<n;mm++)
    {
        int minn=INF;
        int k=-1;
        for(int i=0;i<n;i++)
        {
            if(lowcost[i]<=minn && vis[i]==0)
            {
                minn=lowcost[i];
                k=i;
            }
        }
        vis[k]=1;
        for(int i=0;i<n;i++)
        {
                if(vis[i]==0&&lowcost[i]==lowcost[k]+G[k][i]) //不写vis[i]==0也对,但是会浪费时间
                {
                    if(fee[i]>fee[k]+a[k][i])
                    {
                        fee[i]=fee[k]+a[k][i];
                    }
                }
                else if(vis[i]==0&&lowcost[i]>lowcost[k]+G[k][i])
                {
                    lowcost[i]=lowcost[k]+G[k][i];
                    fee[i]=fee[k]+a[k][i];
                }
        }
    }
}


int main()
{
    scanf("%d %d %d %d",&n,&m,&s,&d);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i!=j)
                G[i][j]=G[j][i]=INF;
        }
    }
    while(m--)
    {
        int x,y,l,f;
        scanf("%d %d %d %d",&x,&y,&l,&f);
        G[x][y]=G[y][x]=l;
        a[x][y]=a[y][x]=f;
    }
    dij();
    printf("%d %d\n",lowcost[d],fee[d]);
    return 0;
}

在这里插入图片描述
在这里插入图片描述
城市间紧急救援这个题我认为比上面那个考的更加全面和具体,比如他要求输出路径,要求输出最短路径条数,比起上个题,此题更有挑战性,做出来收获更大。
代码是我在网上找的,因为很好,比我自己的好太多,所以我只改了一个变量名,侵删。

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;

int a[1001][1001];
int cnt[1001],vis[1001]= {0},cf[1001],ccf[1001],pre[1001];
//最短路径条数,各城市是否经过,各城市的救援队数量,到达该城市时所召集的所有救援队数量,到达该城市前经过的城市编号
int n,m,s,d;
int Dijkstra()
{
    cnt[s]=1;//开始时路径条数为1
    vis[s]=1;//当前在出发城市
    for(int i=0; i<n; i++)
    {
        int min=inf,f=-1;
        for(int j=0; j<n; j++)
        {
            if(vis[j]==0&&a[s][j]<min) //寻找下一个距离最短的城市
            {
                min=a[s][j];
                f=j;//做好下一城市编号的标记
            }
        }
        if(f==-1)break;//与其他未经过的城市不连通,退出循环
        else vis[f]=1;//到达下一城市
        for(int j=0; j<n; j++)
        {
            if(vis[j]==0&&a[s][j]>a[s][f]+a[f][j]) //到达某一城市的最短路径
            {
                a[s][j]=a[s][f]+a[f][j];//最短路径更新
                pre[j]=f;//记录上一个城市编号
                cnt[j]=cnt[f];//拷贝到达上一个城市时的最短路径条数
                ccf[j]=ccf[f]+cf[j];//到达某城市召集的全部救援队数量
            }
            else if(vis[j]==0&&a[s][j]==a[s][f]+a[f][j]) //发现其他的最短路径
            {
                cnt[j]=cnt[j]+cnt[f];//更新到达当前城市时的最短路径条数
                if(ccf[j]<ccf[f]+cf[j]) //最多救援队数量更新
                {
                    pre[j]=f;//记录所经过的上一个城市编号
                    ccf[j]=ccf[f]+cf[j];//更新救援队总数
                }
            }
        }
    }
}


int main()
{
    cin>>n>>m>>s>>d;
    for(int i=0; i<n; i++)
    {
        cin>>cf[i];
        ccf[i]=cf[i];
        cnt[i]=1;
    }
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            if(i!=j)a[i][j]=a[j][i]=inf;//初始化(双向图)
        }
    }
    for(int i=0; i<m; i++)
    {
        int q,w,e;
        cin>>q>>w>>e;
        a[q][w]=a[w][q]=e;
    }
    Dijkstra();
    cout<<cnt[d]<<" "<<ccf[d]+cf[s]<<endl;//注意ccf[d]要与cf[s]相加
    int road[1001];
    int x=0,t=d;
    while(pre[t]!=0) //所经历的城市的从后往前的顺序
    {
        road[x++]=pre[t];
        t=pre[t];
    }
    cout<<s;//出发地
    for(int i=x-1; i>=0; i--)
        cout<<" "<<road[i];
    cout<<" "<<d;//目的地
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值