浙大PAT CCCC L3-014 周游世界 ( 最短路变形 )

题目链接

题意 : 中文题请点链接,挺复杂的...

分析 : 乍一看是个最短路,实际就真的是个最短路。如果没有 “ 在有多条最短路径的时候输出换乘次数最少的” 这一条件的约束,那么这题就是直接建图然后跑个 Dij 就行了,那有了这个约束条件还是要大胆的向最短路思路靠,题目既然需要换乘次数少的,那么我们在进行最短路松弛操作的时候,面对松弛过后最短路径相等的情况就要分开讨论,这时候为了方法取最优值,需要多记录一个信息 ==> 跑到当前点时候换乘次数是多少次,开个数组来记录就行了,其他的还是按最短路来跑。这题就是编码烦了点,不对!是非常烦_(:3 」∠)_

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 10;
struct EDGE{ int v, nxt; }Edge[maxn<<2]; ///向前星存图
struct NODE{ ///跑DIJ时塞在优先队列的结构体
    int v, Pre_v, TransferCnt, Dist; ///当前是哪个点、其前一个点是什么、换乘次数、源点到此点的最短距离

    NODE(int V, int D, int Pv, int TCnt):v(V),Dist(D),Pre_v(Pv),TransferCnt(TCnt){};
    bool operator < (const NODE &rhs) const{
        if(this->Dist == rhs.Dist){ ///最短距离相等应当选择换乘次数小的
            return this->TransferCnt > rhs.TransferCnt; ///由于是优先队列、重载小于号需要注意方向....
        }else{
            return this->Dist > rhs.Dist;
        }
    };
};

int cnt; ///边数量
int Head[maxn]; ///邻接表头
int Pre[maxn]; ///答案路径中每个点的前驱、便于恢复路径
int Dis[maxn]; ///记录Dij中源点到其他点的最短路距离
int TransNum[maxn]; ///到达这个点的时候换乘了多少次
int Line[maxn][maxn]; ///记录路线信息
int path[maxn<<2]; ///存储答案路径
bool vis[maxn]; ///DIJ中的标记数组

inline void init() ///初始化表头和计数变量
{
    memset(Head, -1, sizeof(Head));
    cnt = 0;
}

inline void AddEdge(int from, int to) ///加边函数
{
    Edge[cnt].v = to;
    Edge[cnt].nxt = Head[from];
    Head[from] = cnt++;
}

inline void Run_Dijkstra(int st, int en)
{
    memset(vis, false, sizeof(vis));
    memset(Dis, 0x3f3f3f3f, sizeof(Dis));
    memset(TransNum, 0, sizeof(TransNum));
    priority_queue<NODE> que; while(!que.empty()) que.pop();
    Dis[st] = 0;
    que.push(NODE(st,0,0,0));

    while(!que.empty()){
        NODE T = que.top(); que.pop();

        if(vis[T.v]) continue;
        else vis[T.v] = true;

        for(int i=Head[T.v]; i!=-1; i=Edge[i].nxt){
            int Eiv = Edge[i].v;
            if(Dis[Eiv] > Dis[T.v] + 1){ ///满足松弛条件

                Dis[Eiv] = Dis[T.v] + 1;
                int NewTrans = (T.v==st ? 0 : T.TransferCnt + (Line[T.v][Eiv] != Line[T.Pre_v][T.v])); ///计算新的换乘次数

                que.push(NODE(Eiv, Dis[Eiv], T.v, NewTrans));
                Pre[Eiv] = T.v; ///记录前驱、便于恢复路径
                TransNum[Eiv] = NewTrans; ///记录当前点的换乘次数
            }
            else if(Dis[Eiv] == Dis[T.v] + 1 && ///最短距离与松弛后相等则接下来比较换乘次数
                    TransNum[Eiv] > T.TransferCnt + (Line[T.v][Eiv] != Line[T.Pre_v][T.v])){

                que.push(NODE(Eiv, Dis[Eiv], T.v, T.TransferCnt + (Line[T.v][Eiv] != Line[T.Pre_v][T.v])));
                Pre[Eiv] = T.v; ///改变前驱
                TransNum[Eiv] = T.TransferCnt + (Line[T.v][Eiv] != Line[T.Pre_v][T.v]); ///更新换乘次数
            }
        }
    }

    if(Dis[en] == 0x3f3f3f3f){ ///不可达、输出 No Solution
        puts("Sorry, no line is available.");
        return ;
    }else{
        int top = 0; ///记录路径中节点个数
        int now = en; ///由于记录的是前驱、所以从终点开始恢复路径
        int StNext;
        path[top++] = en;
        while(now != st){
            int temp = Pre[now];
            if(temp==st) StNext = now; ///记录起点的后继 ==> 我接下来的输出满足题目所需的答案有需要
            path[top++] = temp;
            now = temp;
        }

        printf("%d\n", Dis[en]); ///先输出最短距离
        int CurLine = Line[st][StNext]; ///从起点开始记录当前所在的铁路编号
        int CurPoint = st; ///当前的点
        for(int i=top-1; i>=1; i--){
            if(Line[path[i]][path[i-1]] == CurLine) continue; ///如果下一个点和仍然在和之前一样的铁路编号则说明不是换乘点
            else{
                printf("Go by the line of company #%d from %04d to %04d.\n",CurLine, CurPoint, path[i]); ///输出格式需要注意....
                ///printf("Go by the line of company #%d from %d to %d.\n", CurLine, CurPoint, path[i]); ///!!!错误的输出格式!!!
                CurPoint = path[i]; ///更新 CurPoint、CurLine
                CurLine = Line[path[i]][path[i-1]];
            }
        }
        printf("Go by the line of company #%d from %04d to %04d.\n",CurLine, CurPoint, path[0]);
       ///printf("Go by the line of company #%d from %d to %d.\n", CurLine, CurPoint, path[0]); ///!!!错误的输出格式!!!
    }
}

int main(void)
{
    init();
    int n;
    scanf("%d", &n);
    for(int i=1; i<=n; i++){
        int num, A, B;
        scanf("%d %d", &num, &A);
        for(int j=1; j<num; j++){
            scanf("%d", &B);
            AddEdge(A, B);
            AddEdge(B, A);
            Line[A][B] = Line[B][A] = i;
            A = B;
        }
    }

    int Query;
    scanf("%d", &Query);
    while(Query--){
        int A, B;
        scanf("%d %d", &A, &B);
        Run_Dijkstra(A, B);
    }
    return 0;
}

时间: 2024-11-13 08:04:36

浙大PAT CCCC L3-014 周游世界 ( 最短路变形 )的相关文章

浙大PAT CCCC L3-001 凑零钱 ( 0/1背包 &amp;&amp; 路径记录 )

题目链接 分析 : 就是一个 0/1 背包,但是需要记录具体状态的转移情况 这个可以想象成一个状态转移图,然后实际就是记录路径 将状态看成点然后转移看成边,最后输出字典序最小的路径 这里有一个很巧妙的做法 先将所有的硬币升序排序(这一点很重要) 然后在这一条件下,假设当前状态是考虑第 i 个硬币,前一个状态是考虑第 i-1 个硬币 试想对于同一个体积,如果选用的硬币数量越多是不是字典序更小 然后对于如果对于同一体积下,选用硬币数一样多的两种方案 由于我们已经升序排序,如果有一样多硬币的情况,那么

阳光动力2号能够环球航行而不能周游世界

近日,媒体上几乎天天都有阳光动力2号太阳能飞机环球航行 的新闻,但是,太阳能飞机能够环球航行并不等于可以周游世 界,因为,环球航行与周游世界是两个不同的概念.为什么? 比如,阳光动力2号能否飞到中国北京?似乎没有人提出这个问 题.如果太阳能飞机不能飞到北京,那么,我们就不能说:太 阳能飞机可以"周游世界".实际上,阳光动力2号此刻不能飞到 北京.为什么? 顾名思义,所谓"阳光动力"就是由太阳能驱动的意思.言下之 意就是,如果缺少阳光(即阳光强度不够),太阳能飞机就不

浙大PAT考试1013~1016(最伤的一次。。)

我能说我1016WA了几天都不得最后还是拿别人代码交的么. .. 真心找不到那个神数据.. . 自己把整个程序的流程都画出来了.细致推敲是木有问题的啊... 题目地址:点击打开链接 先从1013開始介绍. 题目大意:给你n个城市,m条路,k个询问.每次询问.是假设没有城市q1,,,qk其它城市链接在一起至少须要多少条路. 简单的并查集问题.对节点qi无论,其它的点用并查集.我们所要求的就是有多少个分量.ans个分量则须要ans-1条路就可以.详见代码: AC代码: #include<iostre

浙大PAT考试1077~1080(2014上机复试题目)

题目地址:点击打开链接 还是太弱. . 英文太差.,, 预计要等待被虐了.. 1077 找最长的公共后缀,暴力就能够写: #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<string> using namespace std; char a[105][1005]; int milen;

浙大 PAT Advanced level 1026. Table Tennis (30)

A table tennis club has N tables available to the public. The tables are numbered from 1 to N. For any pair of players, if there are some tables open when they arrive, they will be assigned to the available table with the smallest number. If all the

浙大pat甲级题目---1020. Tree Traversals (25)

Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, you are supposed to output the level order traversal sequence of the corresponding binary tree. Input Specification: Each

欢迎来到Git的世界

魔都的梅雨季简直了!对于杨梅爱好者来说,这是一个幸福的季节,然而,对于一个北方的妹子,实在忍受不了他的"诗".每到下雨天,最怕的就是衣服.鞋子被打湿,可是昨天在网上看到一张照片后,雨天阴霾的心情瞬间放晴.只要心情是晴朗的,人生就没有雨天. 言归正传,开启我的Git学习之路喽...... Git的版本控制之道 Git作为一种新型的,轻量级的分布式版本控制系统(DVCS),深受攻城狮们喜爱.版本控制系统就好比银行的保险箱,保管价值连城的资产.而对于程序员来说,源代码就是这样的资产,由版本控

简谈DFS

所谓DFS就是"不撞南墙不回头"的一种搜索.其时间复杂度为O(V+E). 能算出从起点到终点的全部路径,在算法执行的过程中需要一个visit[vi]数组来维护每个结点的访问情况,这样就能避免重复访问.但需要注意的是对于同一起点到同一终点有多条路径的时候,每次递归回溯时要重置visit[vi]的状态.并且可以使用vector来存储每次经过的节点.两个同类型的vector数组可以直接比较.直接赋值的,所以DFS也就可以简单的求出最佳路径. DFS在递归过程中的还存在一个难点就是结束递归开始

如果回到十八岁,我要对自己说......

I like to joke that I am who I am today because I did everything wrong in my 20's. I've always been fearless, and it often got me in trouble. I wasn't afraid to start a business, borrow a bunch of money, or quit a well-paying job to travel the world.