题目链接: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110697#problem/A
-------------------------------------------------------------------------------------------------------
给定一个有向正权图和起点终点 求最短路以及比最短路长$1$的路径的个数(允许一条边走两次)
我们知道 $dijkstra$ 是基于一种贪心的思想 当某点成为当前所有未被使用的点中距离最近的点时
它就可以开始用来更新其他的点 并且它的距离是不可能再改变的
如果要求路径数的话 到这个点的最短路径的数量显然也是不会再变的
因此记录最短路径数量就有点像$DAG$上做的$dp$
至于求次短路 我们可以把每个点的次短路单独抽出来作为新的$n$个点(不过仍然受原来的求最短路的点影响)
这样在新的图上跑最短路就可以一次同时得到最短路和次短路了
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 const int N = 1010, E = 10010; 7 int firste[N], nexte[E], v[E], w[E]; 8 int dist[N << 1], cnt[N << 1]; 9 bool used[N << 1]; 10 int t, n, m, e; 11 void build(int x,int y, int z) 12 { 13 nexte[++e] = firste[x]; 14 firste[x] = e; 15 v[e] = y; 16 w[e] = z; 17 } 18 void dijkstra(int s) 19 { 20 memset(dist, 0x3f, sizeof dist); 21 memset(cnt, 0, sizeof cnt); 22 memset(used, 0, sizeof used); 23 dist[s] = 0; 24 cnt[s] = 1; 25 int u = s, tu, mdist; 26 for(int tt = 1; tt < n * 2; ++tt) 27 { 28 mdist = 1e9 + 10; 29 used[u] = 1; 30 if(u <= n) 31 for(int p = firste[u]; p; p = nexte[p]) 32 { 33 if(dist[v[p]] > dist[u] + w[p]) 34 { 35 dist[v[p] + n] = dist[v[p]]; 36 cnt[v[p] + n] = cnt[v[p]]; 37 dist[v[p]] = dist[u] + w[p]; 38 cnt[v[p]] = cnt[u]; 39 } 40 else if(dist[v[p]] == dist[u] + w[p]) 41 cnt[v[p]] += cnt[u]; 42 else if(dist[v[p] + n] > dist[u] + w[p]) 43 { 44 dist[v[p] + n] = dist[u] + w[p]; 45 cnt[v[p] + n] = cnt[u]; 46 } 47 else if(dist[v[p] + n] == dist[u] + w[p]) 48 cnt[v[p] + n] += cnt[u]; 49 } 50 else 51 for(int p = firste[u - n]; p; p = nexte[p]) 52 { 53 if(dist[v[p] + n] > dist[u] + w[p]) 54 { 55 dist[v[p] + n] = dist[u] + w[p]; 56 cnt[v[p] + n] = cnt[u]; 57 } 58 else if(dist[v[p] + n] == dist[u] + w[p]) 59 cnt[v[p] + n] += cnt[u]; 60 } 61 for(int i = 1; i <= n * 2; ++i) 62 if(!used[i] && dist[i] < mdist) 63 { 64 mdist = dist[i]; 65 tu = i; 66 } 67 u = tu; 68 } 69 } 70 int main() 71 { 72 scanf("%d", &t); 73 while(t--) 74 { 75 e = 1; 76 memset(firste, 0, sizeof firste); 77 scanf("%d%d", &n, &m); 78 int x, y, z; 79 while(m--) 80 { 81 scanf("%d%d%d", &x, &y, &z); 82 build(x, y, z); 83 } 84 int s, f; 85 scanf("%d%d", &s, &f); 86 dijkstra(s); 87 printf("%d\n", cnt[f] + cnt[f + n] * (dist[f + n] == dist[f] + 1)); 88 } 89 return 0; 90 }