zoukankan      html  css  js  c++  java
  • 观光

    链接

    https://www.acwing.com/problem/content/description/385/

    题目

    “您的个人假期”旅行社组织了一次比荷卢经济联盟的巴士之旅。

    比荷卢经济联盟有很多公交线路。

    每天公共汽车都会从一座城市开往另一座城市。

    沿途汽车可能会在一些城市(零或更多)停靠。

    旅行社计划旅途从 S 城市出发,到 F 城市结束。

    由于不同旅客的景点偏好不同,所以为了迎合更多旅客,旅行社将为客户提供多种不同线路。

    游客可以选择的行进路线有所限制,要么满足所选路线总路程为 S 到 F 的最小路程,要么满足所选路线总路程仅比最小路程多一个单位长度。

    如上图所示,如果S = 1,F = 5,则这里有两条最短路线1->2->5,1->3->5,长度为6;有一条比最短路程多一个单位长度的路线1->3->4->5,长度为7。

    现在给定比荷卢经济联盟的公交路线图以及两个城市 S 和 F,请你求出旅行社最多可以为旅客提供多少种不同的满足限制条件的线路。

    输入格式
    第一行包含整数 T,表示共有 T 组测试数据。

    每组数据第一行包含两个整数 N 和 M,分别表示总城市数量和道路数量。

    接下来 M 行,每行包含三个整数 A,B,L,表示有一条线路从城市 A 通往城市 B,长度为 L。

    需注意,线路是 单向的,存在从A到B的线路不代表一定存在从B到A的线路,另外从城市A到城市B可能存在多个不同的线路。

    接下来一行,包含两个整数 S 和 F,数据保证 S 和 F 不同,并且S、F之间至少存在一条线路。

    输出格式
    每组数据输出一个结果,每个结果占一行。

    数据保证结果不超过(10^9)

    数据范围
    (2≤N≤1000,)
    (1≤M≤10000,)
    (1≤L≤1000,)
    (1≤A,B,S,F≤N)
    输入样例:

    2
    5 8
    1 2 3
    1 3 2
    1 4 5
    2 3 1
    2 5 3
    3 4 2
    3 5 4
    4 5 3
    1 5
    5 6
    2 3 1
    3 2 1
    3 1 10
    4 5 2
    5 2 7
    5 2 7
    4 1
    

    输出样例:

    3
    2
    

    思路

    关于最短路计数问题可以看这篇:https://www.cnblogs.com/jjl0229/p/12755656.html
    这道题目边权不全为1且没有负权边,可以用迪杰斯特拉。具体做法就是拆点,把每个点拆成最短距离和次短距离,每次将更新的最短或次短点作为一个独立的点加入堆中,每次从堆中取出一个最短或次短作为一个独立的点去更新其他点。每次优先更新可达点的最短距离点,如果可以更新最短距离,那么将该点的次短替换成最短的信息,再去更新最短距离点,否则再判断是否可以更新次短距离点。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> PII;
    const int N=1010,M=10010;
    int h[N],w[M],nex[M],e[M],idx;
    int cnt[N][2],d[N][2],st[N][2],S,F;
    void add(int u,int v,int t){
        w[idx]=t;
        e[idx]=v;
        nex[idx]=h[u];
        h[u]=idx++;
    }
    struct ac{
        int u,d,type;
        bool operator<(const ac& b) const {
            return d>b.d;
        }
    };
    priority_queue<ac> heap;
    void dij(){
        memset(d,0x3f,sizeof d);
        memset(cnt,0,sizeof cnt);
        memset(st,0,sizeof st);
        cnt[S][0]=1;
        d[S][0]=0;
        heap.push({S,0,0});
        while(heap.size()){
            int u=heap.top().u,t=heap.top().type;
            heap.pop();
            if(st[u][t]) continue;
            st[u][t]=1;
            for(int i=h[u];~i;i=nex[i]){
                int v=e[i];
                if(d[v][0]>d[u][t]+w[i]){
                    d[v][1]=d[v][0];
                    cnt[v][1]=cnt[v][0];
                    d[v][0]=d[u][t]+w[i];
                    cnt[v][0]=cnt[u][t];
                    heap.push({v,d[v][0],0});
                    heap.push({v,d[v][1],1});
                }
                else if(d[v][0]==d[u][t]+w[i]){
                    cnt[v][0]+=cnt[u][t];
                }
                else if(d[v][1]>d[u][t]+w[i]){
                    d[v][1]=d[u][t]+w[i];
                    cnt[v][1]=cnt[u][t];
                    heap.push({v,d[v][1],1});
                }
                else if(d[v][1]==d[u][t]+w[i]){
                    cnt[v][1]+=cnt[u][t];
                }
            }
        }
    }
    int main(){
        int T;
        cin>>T;
        while(T--){
            int n,m;
            cin>>n>>m;
            memset(h,-1,sizeof h);idx=0;
            for(int i=1;i<=m;++i){
                int u,v,t;
                cin>>u>>v>>t;
                add(u,v,t);
            }
            cin>>S>>F;
            dij();
            if(d[F][0]==d[F][1]-1){
                cout<<cnt[F][0]+cnt[F][1]<<endl;
            }
            else cout<<cnt[F][0]<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    修改默认runlevel
    shell数学运算
    Ubuntu碎碎念
    编译Linux-2.6.23内核中遇见的错误
    CentOS设置静态IP
    多线程--对象锁和类锁
    [Unity移动端]Touch类
    [Lua]string与中文
    MQTT 5.0 新特性(四)Clean Start 与 Session Expiry Interval
    EMQ 9 月 新发 | EMQ X Enterprise 3.4.0 功能概览
  • 原文地址:https://www.cnblogs.com/jjl0229/p/12757722.html
Copyright © 2011-2022 走看看