思路
次短路结合路径统计,考虑 Dijkstra 算法。
定义 $dist_0$ 、 $dist_1$ 分别表示最短路、次短路长度, $cnt_0$ 、 $cnt_1$ 分别表示最短路、次短路路径数目。每次从优先队列取出元素时,考虑以下 $4$ 种情况。
首先,考虑出现了比当前最短路长度更小的路径,则上述 $4$ 种元素都需更新。其次,考虑出现了与当前最短路长度相同的路径,则更新最短路数目。再次,考虑出现了比最短路长度大但比次短路长度小的路径,则更新次短路长度、数目。最后,考虑出现了与当前次短路长度相同的路径,则更新最短路数目。
code
#include<bits/stdc++.h>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
typedef pair<int,PII> PIII;
const int N=1010,M=10010,INF=0x3f3f3f3f;
int T,n,m,s,t;
int h[N],e[M],w[M],ne[M],idx;
int dist[2][N],cnt[2][N];
bool st[2][N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra(int u,int v)
{
memset(dist,0x3f,sizeof dist);
memset(st,0,sizeof st);
memset(cnt,0,sizeof cnt);
cnt[0][u]=1;
dist[0][u]=0;
priority_queue<PIII,vector<PIII>,greater<PIII> > heap;
heap.push({0,{0,u}});
while(heap.size())
{
PIII tt=heap.top();
heap.pop();
PII now=tt.second;
int ver=now.second,num=now.first,distance=tt.first;
if(st[num][ver]) continue;
st[num][ver]=true;
for(int i=h[ver];~i;i=ne[i])
{
int j=e[i];
if(dist[0][j]>distance+w[i])
{
dist[1][j]=dist[0][j];
cnt[1][j]=cnt[0][j];
heap.push({dist[1][j],{1,j}});
dist[0][j]=distance+w[i];
cnt[0][j]=cnt[num][ver];
heap.push({dist[0][j],{0,j}});
}
else if(dist[0][j]==distance+w[i]) cnt[0][j]+=cnt[num][ver];
else if(dist[1][j]>distance+w[i])
{
dist[1][j]=distance+w[i];
cnt[1][j]=cnt[num][ver];
heap.push({dist[1][j],{1,j}});
}
else if(dist[1][j]==distance+w[i]) cnt[1][j]+=cnt[num][ver];
}
}
if(dist[0][v]+1==dist[1][v]) return cnt[0][v]+cnt[1][v];
else return cnt[0][v];
}
int main()
{
cin.tie(0)->sync_with_stdio(0);
cin>>T;
while(T--)
{
cin>>n>>m;
memset(h,-1,sizeof h);
idx=0;
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
cin>>s>>t;
cout<<dijkstra(s,t)<<'\n';
}
return 0;
}