AcWing 920. 最优乘车(建图,特殊处理输入,bfs求最短路)

30 篇文章 0 订阅
17 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述

题意:

给定路线数m,站点数nm单程路线会经过哪些站点,问从起点1终点n最少要换乘几次**。

思路:

换乘多少次 可以转换为 乘坐过多少次车减1

步骤:

  • 1、在同一条路线中,任意一个 在此路线上的车站 均能 沿着该路线的方向 到达后面的车站,权值都是1,表示 只乘坐一次车

    • 解释:以样例 4 7 3 6 为例,分别将 4 ~ 7、4 ~ 3、4 ~ 6、7 ~ 3、7 ~ 6、3 ~ 6 连一条边,权值为 1:表示从 车站4做到 车站7 只要乘一次车,表示从 车站4 做到 车站3 只要乘一次车等等…
  • 2、不是同一线路上 或者 在同一路线上但是不符合上面一条 的车站 相互之间的权值赋为0,表示 两个节点之间不连通

  • 3、通过建图,由于权值均是1,我们使用最常规的bfs就行了,求出1号点到n号点最少乘过多少次车(当然用其他的最短路算法也是可以的,只不过要由数据范围来确定选择哪一种

  • 4、由换乘次数 = 乘车次数 - 1,最后dist[n]-1(代码之中为t.step-1,是一样的)即为所求。(初始时dist数组均置为inf,当然-1也是可以的)

注意:

这道题的输入,一条路线经过若干站点,但是站点个数不给,所以可以考虑stringstream 处理读入

初始用cin输入m、n两个变量后如果想用getline读取一整行,在此之前还应当用getline吃掉输入m、n后产生的回车符。(代码中有体现)

建图的时候,就像我们上面分析的一样,不一定非要建成真正的路线图,要根据实际问题进行抽象

时间复杂度:

O(M∗N^2)瓶颈在于main函数中的建图过程,而不是bfs

假设1条路线经过所有的站,则边数为(N−1)+(N−2)+…+1=N∗(N−1)/2

题目共有M条,因此运行的最多次数是M∗N∗(N−1)/2
因此时间复杂度是 O(M∗N^2)

代码:

#include<bits/stdc++.h>

using namespace std;
#define inf 0x3f3f3f3f
int m, n;
const int N = 510;
int g[N][N];
int stop[N];
int dist[N];//记录步数
struct node
{
        int num, step;//编号、步数
};
queue<node> q;

void bfs()
{
        while(!q.empty())
        {
                node t = q.front();
                q.pop();
                if(t.num == n){//到达了终点,将答案输出
                        cout<<t.step-1<<endl;
                        return ;
                }
                for(int i=1; i<=n; ++i)
                {
                        if(g[t.num][i]&&dist[i]==inf){//如果边权为1且没有被走过我们就走过去,只要两个判断就行
                                q.push({i, t.step+1});
                                dist[i] = t.step+1;
                        }
                }
        }
        cout<<"NO"<<endl;
        return ;
}

int main()
{
        cin>>m>>n;
        string line ;
        getline(cin, line);// 一定要先过滤掉回车

        for(int i=0;i<m;++i)
        {
                getline(cin, line);
                stringstream ssin(line);
                int cnt = 0, p;
                while(ssin>>p) stop[cnt++] = p;
                for(int j=0; j<cnt; ++j){
                        for(int k=j+1; k<cnt; ++k){
                                g[stop[j]][stop[k]] = 1;
                        }
                }
        }
        memset(dist, 0x3f, sizeof dist);//初始化为0x3f3f3f3f或-1,都可以
        dist[1] = 0;
        q.push({1, 0});
        bfs();

        return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值