A1131 Subway Map (30 分| dfs深度优先探索,附详细注释,逻辑分析)

写在前面

  • 思路分析
    • 找出1条路线,使得对任何给定的起点和终点,可以找出中途经停站最少的路线
      • 如果经停站1样多,则取需要换乘线路次数最少路线
    • 1遍DFS
      • DFS过程中维护2个变量
        • minCnt-中途经停的最少站
        • minTransfer-需要换乘的最小次数
      • 0.计算1条线路换乘次数:
        • 在line[10000][10000]的数组中保存每两个相邻站中间的线路是几号线
        • 从头到尾遍历最终保存的路径, preLine为前1小段的线路编号,如果当前的结点和前1个结点组成的这条路的线路编号和preLine不同,说明有1个换乘,就将cnt+1,最后遍历完累加的cnt即是换乘的次数
        • 内存超限,选用unordered_map<int, int> line存储方式,第1个int存储线路,每次将前四位存储第1个线路,后四位存储第2个线路,使用a[i-1]*10000+a[i]的方式存储,第2个int用来保存两个相邻中间的线路是几号线
      • 1.计算出1条线路中途停站的次数:
        • 在dfs的时候有个变量cnt,表示当前路线是所需乘的第几个站,每次dfs时候将cnt+1表示向下遍历1层
          • cnt就是当前中途停站的次数
      • 2.输出结果:
        • 和计算线路换乘次数思路一样,每当preLine和当前Line值不同就输出1句话
        • 保存preTransfer表示上1个换乘站
        • 最后输出preTransfer和最后1个站之间的路即使最后1个站并不是换乘站
  • 题目较长、较难,学习ing

测试用例

  • input:
    4
    7 1001 3212 1003 1204 1005 1306 7797
    9 9988 2333 1204 2006 2005 2004 2003 2302 2001
    13 3011 3812 3013 3001 1306 3003 2333 3066 3212 3008 2302 3010 3011
    4 6666 8432 4011 1306
    3
    3011 3013
    6666 2001
    2004 3001
    
    output:
    2
    Take Line#3 from 3011 to 3013.
    10
    Take Line#4 from 6666 to 1306.
    Take Line#3 from 1306 to 2302.
    Take Line#2 from 2302 to 2001.
    6
    Take Line#2 from 2004 to 1204.
    Take Line#1 from 1204 to 1306.
    Take Line#3 from 1306 to 3001.
    

ac代码

  • #include <iostream>
    #include <vector>
    #include <unordered_map>
    using namespace std;
    
    vector<vector<int>> v(10000);
    int visit[10000], minCnt, minTransfer, start, end1;
    unordered_map<int, int> line;
    vector<int> path, tmpPath;
    
    // 统计换乘路线次数
    int transferCnt(vector<int> a)
    {
        int cnt = -1, preLine = 0;
        for(int i=1; i<a.size(); i++)
        {
            if(line[a[i-1]*10000+a[i]] != preLine) cnt++;
            preLine = line[a[i-1]*10000+a[i]];
        }
        return cnt;
    }
    
    void dfs(int node, int cnt)
    {
        // 终点 / 换乘次数小于最小值 / 换乘次数等于最小值且换乘路线小于最小换乘路线
        if(node == end1 && (cnt < minCnt || (cnt == minCnt && transferCnt(tmpPath)<minTransfer)))
        {
            minCnt = cnt;
            minTransfer = transferCnt(tmpPath);
            path = tmpPath;
        }
        if(node == end1) return;
        for(int i=0; i<v[node].size(); i++)
        {
            if(visit[v[node][i]] == 0)
            {
                visit[v[node][i]] = 1;
                tmpPath.push_back(v[node][i]);
    
                // 不太懂
                dfs(v[node][i], cnt+1);
                visit[v[node][i]] = 0;
                tmpPath.pop_back();
            }
        }
    }
    
    int main()
    {
        int n, m, k, pre, tmp;
        scanf("%d", &n);
    
        // 批量读入线路
        for(int i=0; i<n; i++)
        {
            scanf("%d%d", &m, &pre);
            for(int j=1; j<m; j++)
            {
                scanf("%d", &tmp);
                v[pre].push_back(tmp);
                v[tmp].push_back(pre);
                // 标记线路
                line[pre*10000+tmp] = line[tmp*10000+pre] = i+1;
                // 更新后继结点
                pre = tmp;
            }
        }
    
        scanf("%d", &k);
        for(int i=0; i<k; i++)
        {
            scanf("%d%d", &start, &end1);
            minCnt = 9999, minTransfer = 9999;
            tmpPath.clear();
            tmpPath.push_back(start);
    
            visit[start] = 1;
            dfs(start, 0);
    
            visit[start] = 0;
            printf("%d\n", minCnt);
    
            int preLine = 0, preTransfer = start;
            for(int j=1; j<path.size(); j++)
            {
                if(line[path[j-1]*10000+path[j]] != preLine)
                {
                    if(preLine != 0)
                        printf("Take Line#%d from %04d to %04d.\n", preLine, preTransfer, path[j-1]);
                    preLine = line[path[j-1]*10000+path[j]];
                    preTransfer = path[j-1];
                }
            }
            printf("Take Line#%d from %04d to %04d.\n", preLine, preTransfer, end1);
        }
    
        return 0;
    }
    	```
    
  • 学习代码
    • 看不太懂,,,后续学习
    #include <stdio.h>
    #include <stdlib.h>
    #define inf 0x3f3f3f3f
    #define MAX 10002
    int n,m,k;
    int link[MAX][11],linknum[MAX];//邻接元素 邻接元素个数
    int vis[MAX],path[MAX],num,ans[MAX],ant;
    int line[MAX][11];//与邻接元素 所属的线路
    int getline(int a,int b)  //获得线路号
    {
        for(int i = 0; i < linknum[a]; i ++)
            if(link[a][i] == b)return line[a][i];
    }
    void dfs(int stop,int lastline,int lnum,int snum,int des)  //stop 是当前车站 lastline是上1条线路 lnum是当前经过的中转站数 snum是站点数 des是目的地
    {
        path[snum] = stop;
        if(snum > ant || snum == ant && lnum > num)return;
        if(stop == des)
        {
            ant = snum;
            num = lnum;
            for(int i = 0; i <= snum; i ++)
            {
                ans[i] = path[i];
            }
            return;
        }
        for(int i = 0; i < linknum[stop]; i ++)
        {
            if(!vis[link[stop][i]])
            {
                vis[link[stop][i]] = 1;
                int d = getline(stop,link[stop][i]);
                if(lastline != d)dfs(link[stop][i],d,lnum + 1,snum + 1,des);
                else dfs(link[stop][i],d,lnum,snum + 1,des);
                vis[link[stop][i]] = 0;
            }
        }
    }
    int main()
    {
        int a,b;
        scanf("%d",&n);
        for(int i = 1; i <= n; i ++)
        {
            scanf("%d",&m);
            scanf("%d",&a);
            for(int j = 1; j < m; j ++)
            {
                scanf("%d",&b);
                link[a][linknum[a] ++] = b;
                line[a][linknum[a] - 1] = i;
                link[b][linknum[b] ++] = a;
                line[b][linknum[b] - 1] = i;
                a = b;
            }
        }
        scanf("%d",&k);
        while(k--)
        {
            scanf("%d%d",&a,&b);
            ant = num = MAX;
            dfs(a,-1,-1,0,b);
            printf("%d\n",ant);
            int line1 = getline(ans[0],ans[1]);
            for(int i = 2; i <= ant; i ++)
            {
                int line2 = getline(ans[i - 1],ans[i]);
                if(line1 != line2)
                {
                    printf("Take Line#%d from %04d to %04d.\n",line1,a,ans[i - 1]);
                    a = ans[i - 1];
                    line1 = line2;
                }
            }
            printf("Take Line#%d from %04d to %04d.\n",line1,a,ans[ant]);
        }
        return 0;
    }
    
发布了328 篇原创文章 · 获赞 107 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/qq_24452475/article/details/100602036