题意:
给出一个n点m边的有向图,求s到t的最短路和长度为最短路+1的路的种类数;
n<=1000,m<=10000;
思路:
1.dijkstra 更新距离时,多加一个坑,放置次短距离.
2.因为多了一个坑,枚举最小值时,多了一倍需要枚举
3.更新距离时,要按照一定的顺序 以免重复更新
代码如下
/*
* Author : Echo
* Email : 1666424499@qq.com
* Description :
* Created Time : 2017/10/6 9:26:12
* Last Modify : 2017/10/6 15:25:58
* File Name : a.cpp
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <time.h>
#define LL long long
#define mem(a,k) memset(a,k,sizeof(a))
using namespace std;
const int maxint = -1u>>1;
const int maxn=1e3+100;
const int maxm=1e4+100;
bool vis[maxn][3];
int dis[maxn][3];
int ans[maxn][3];
struct edge{
int to,next,value;
void set(int a,int b,int c){
to=a,value=b;next=c;
}
}an[maxm];
int cnt=0,head[maxn];
int src,sink;
void addedge(int u,int v,int value){
an[cnt].set(v,value,head[u]);
head[u]=cnt++;
}
void dijkstra(int n){
for(int i=1;i<=n;i++){
for(int j=1;j<=2;j++){
dis[i][j]=1e9;
vis[i][j]=0;
ans[i][j]=0;
}
}
dis[src][1]=0;
ans[src][1]=1;
for(int i=1;i<=2*n;i++){
int u,minn=1e9,x;
for(int j=1;j<=n;j++){
if(dis[j][1]<minn&&vis[j][1]==0){
minn=dis[j][1];
u=j;
x=1;
}
else if(dis[j][2]<minn&&vis[j][2]==0){
minn=dis[j][2];
u=j;
x=2;
}
}
vis[u][x]=1;
if(minn==1e9)break;
for(int j=head[u];j!=-1;j=an[j].next){
int v=an[j].to;
if(dis[v][1]>minn+an[j].value){
dis[v][2]=dis[v][1];
ans[v][2]=ans[v][1];
dis[v][1]=minn+an[j].value;
ans[v][1]=ans[u][x];
}
else if(dis[v][1]==minn+an[j].value){
ans[v][1]+=ans[u][x];
}
else if(dis[v][2]>minn+an[j].value){
dis[v][2]=minn+an[j].value;
ans[v][2]=ans[u][x];
}
else if(dis[v][2]==minn+an[j].value){
ans[v][2]+=ans[u][x];
}
}
}
}
int main(){
int t;
cin>>t;
while(t--){
memset(head,-1,sizeof(head));
cnt=1;
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
}
scanf("%d%d",&src,&sink);
dijkstra(n);
if(dis[sink][1]==dis[sink][2]-1) ans[sink][1]+=ans[sink][2];
//printf("%d %d %d %d\n",dis[sink][1],dis[sink][2],ans[sink][1],ans[sink][2]);
printf("%d\n",ans[sink][1]);
}
return 0;
}
/*
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
*/