题意分析
从起点到终点,最短路径的条数和比最短路径多一个长度的条数之和
算法分析
最短路径的条数:在更新最短路时,如果遇到dist[j]=dist[i]+w的情况时,此时cnt(记录最短路条数)的数量进行更新cnt+=count
比最短路径多一个长度的条数:边权为整数,比最短路大1,即在次短路中寻找比最短路长度少1的条数就行累加
综上,本题的根本是求最短路与次短路
利用dij计算最短路,同时也把次短路一起算出来:
用两个变量分别存储最小值和次小值,遍历到新的最小值时,把当前最小值设为次小值,原次小值丢弃,然后再设置新的最小值;遍历到无法更新最小值但可以更新次小值的值时,把它设为次小值。
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=20010;
int n,m,s,t;
int cnt[N][2],dist[N][2];//d[i][0]存储1~i最短路, d[i][1]存储1~i次短路
bool st[N][2];
//对于每个点记录三个信息,pair不够用,用struct
struct ver{
int id,type,dist;//对于每个点记录标号,最短路/次短路,距离
bool operator> (const ver &w) const
{
return dist>w.dist;
}
};
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
int dij()
{
memset(st,0,sizeof st);
memset(dist,0x3f,sizeof dist);
memset(cnt,0,sizeof cnt);
//对于源点只有最短路,没有次短路
dist[s][0]=0;//源点的最短路距离为0
cnt[s][0]=1;//源点的最短路条数为1
priority_queue<ver,vector<ver>,greater<ver> >q;
q.push({s,0,0});
while(q.size())
{
ver t=q.top();
q.pop();
int tver=t.id,ttype=t.type,distance=t.dist,count=cnt[tver][ttype];
if(st[tver][ttype]) continue;
st[tver][ttype]=true;
for(int i=h[tver];~i;i=ne[i])
{
int j=e[i];
//有更短得最短路
if(dist[j][0]>distance+w[i])
{
//把当前最短路得值先给次短路
dist[j][1]=dist[j][0];
cnt[j][1]=cnt[j][0];
q.push({j,1,dist[j][1]});
//更新最短路
dist[j][0]=distance+w[i];
cnt[j][0]=count;
q.push({j,0,dist[j][0]});
}
//
else if(dist[j][0]==distance+w[i])
{
cnt[j][0]+=count;
}
//当前新值大于最短路,小于次短路,
else if(dist[j][1]>distance+w[i])
{
dist[j][1]=distance+w[i];
cnt[j][1]=count;
q.push({j,1,dist[j][1]});
}
else if(dist[j][1]==distance+w[i])
{
cnt[j][1]+=count;
}
}
}
int res=cnt[t][0];
if(dist[t][0]+1 == dist[t][1]) res+=cnt[t][1];
return res;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int ts;
cin>>ts;
while(ts--)
{
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<<dij()<<endl;
}
return 0;
}