观光(最短路求方案数2)

题目描述

“您的个人假期”旅行社组织了一次比荷卢经济联盟的巴士之旅。
比荷卢经济联盟有很多公交线路。
每天公共汽车都会从一座城市开往另一座城市。
沿途汽车可能会在一些城市(零或更多)停靠。
旅行社计划旅途从 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之间至少存在一条线路。

输出格式

每组数据输出一个结果,每个结果占一行。
数据保证结果不超过109。

数据范围

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

题目分析

如果之前没做过最短路求方案数这类题目的话,建议先看看这个题:最短路计数(本题的低配版,该题中与本题相同的知识点就不重复说了)。
这道题目其实就是让我们求最短路和次短路的方案数。
因此这道题的配置几乎和最短路计数是一样的:
dist[][2] //记录最短路和次短路、cnt[][2] //记录最短路和次短路的方案数、st[][2] //判重数组
这道题也是只能用bfs和dijkstra算法来求解,(不知道为什么不能用spfa可以看上面的那道题)但是这道题的边都是有权边了,不能用bfs。因此这道题我们要用dijkstra算法

用dijkstra算法之前我们需要确定一件事情:因为这道题要求两种路径(最短路和次短路),因此dijkstra算法中的优先队列不能只保存点的编号id和最短距离dist,我们还需要记录类型type来表示当前这个路径是最短路还是次短路(统一用0表示最短路,1表示次短路)。

把前面的准备条件都想清楚之后,这道题其实也就没什么难度了。剩下的就是dijkstra算法求解答案了:
(dijkstra算法的基本框架和流程就不都说了,直接讲与普通dijkstra算法不同的地方。)
从优先队列中取出队头元素,假设编号为u,枚举其所有相邻节点v。

  1. 如果dist[u][type]+d[u][v]<dist[v][0],那么更新dist[v][0]=dist[u][type]+d[u][v] 和 dist[v][1]=原v的最短路(原dist[v][0])。
    而cnt[v][0]=cnt[u][type];cnt[v][1]=原v最短路的方案数(原cnt[v][0])
  2. 如果dist[u][type]+d[u][v]==dist[v][0],那么dist[v]的值都不需要更新。
    而cnt[v][0]要加上cnt[u][type];cnt[v][1]不需要变。
  3. 如果dist[u][type]+d[u][v]<dist[v][1],那么需要更新dist[v][1]=dist[u][type]+d[u][v] (dist[v][0]不需要变)。
    而cnt[v][1]=cnt[u][type];(cnt[v][0]不变)
  4. 如果dist[u][type]+d[u][v]==dist[v][1],那么dist[v]的值都不需要更新。
    而cnt[v][1]要加上cnt[u][type];cnt[v][0]不变。

全部求完之后,查看dist[终点][0]与dist[终点][1]+1是否相等。如果相等那么答案为cnt[终点][0]+cnt[终点][1];否则答案为cnt[终点][0]。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#define LL long long
#define ULL unsigned long long
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
const int N=1e3+5,M=2e4+5,INF=0x3f3f3f3f;
struct Node{
    
    				//将优先队列中需要的变量封装成结构体
    int id,type,dist;
    bool operator>(const Node &a) const
    {
    
     return dist>a.dist;}
};
int h[N],e[M],w[M],ne[M],idx;
int dist[N][2],cnt[N][2];
bool st[N][2];
void add(int a,int b,int c)
{
    
    
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
int dijkstra(int s,int t)		//dijkstra算法求最/次短路及其方案数
{
    
    
    memset(st,0,sizeof st);
    memset(cnt,0,sizeof cnt);
    memset(dist,0x3f,sizeof dist);
    priority_queue<Node,vector<Node>,greater<Node> >heap;
    dist[s][0]=0; cnt[s][0]=1;
    heap.push({
    
    s,0,0});
    while(heap.size())
    {
    
    
        Node t=heap.top();
        heap.pop();

        int u=t.id,type=t.type,distance=t.dist,count=cnt[u][type];
        if(st[u][type]) continue;
        st[u][type]=true;

        for(int i=h[u];~i;i=ne[i])
        {
    
    
            int v=e[i];
            if(dist[v][0]>distance+w[i])
            {
    
    
                cnt[v][1]=cnt[v][0];
                dist[v][1]=dist[v][0];
                heap.push({
    
    v,1,dist[v][1]});
                cnt[v][0]=count;
                dist[v][0]=distance+w[i];
                heap.push({
    
    v,0,dist[v][0]});
            }
            else if(dist[v][0]==distance+w[i]) cnt[v][0]+=count;
            else if(dist[v][1]>distance+w[i])
            {
    
    
                cnt[v][1]=count;
                dist[v][1]=distance+w[i];
                heap.push({
    
    v,1,dist[v][1]});
            }
            else if(dist[v][1]==distance+w[i]) cnt[v][1]+=count;
        }
    }
    int res=cnt[t][0];
    if(dist[t][0]+1==dist[t][1]) res+=cnt[t][1];
    return res;
}
int main()
{
    
    
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
        idx=0;
        memset(h,-1,sizeof h);
        int n,m;
        scanf("%d %d",&n,&m);
        while(m--)				//建图
        {
    
    
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            add(u,v,w);
        }
        int s,t;
        scanf("%d %d",&s,&t);
        cout<<dijkstra(s,t)<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/li_wen_zhuo/article/details/109626542
今日推荐