luogu【P1144】最短路计数
这道题 一道有关于最短路的图论问题。 要求从1开始求解最短路的条数。
这个题十分有趣,首先,跑裸的spfa(或者dijkstra)算出从1开始的最短路的长度。
再其次,计数的话,可以用记忆化搜索(相当于DAG dp)我们现在所遍历的路径长度要刚好是最短路的长度。
(这个程序中会有体现的)
这个题我前面一直在TLE,就是没有用记忆化,暴力去找路径。(第一遍还因为没算空间MLE。。TAT)
后来优化后 时间效率挺不错。(300多ms)
下面上代码:
1 #include <bits/stdc++.h> 2 #define Set(a, v) memset(a, v, sizeof(a)) 3 #define For(i, l, r) for(int i = (l); i <= (int)(r); ++i) 4 #define Fordown(i, r, l) for(int i = (r); i >= (int)(l); --i) 5 using namespace std; 6 7 inline int read(){ 8 int x = 0, fh = 1; char ch; 9 for(; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1; 10 for(; isdigit(ch); ch = getchar()) x = (x<<1) + (x<<3) + (ch^'0'); 11 return x * fh; 12 } 13 14 const int N = 1000000, M = 2000000 << 1, inf = 0x3f3f3f3f; 15 const int mod = 100003; 16 17 struct graph { 18 int to[M], Head[N], Next[M], val[M], e; 19 void init() { 20 e = 0; 21 Set(Head, 0); 22 } 23 void add_edge (int u, int v, int w) { 24 to[++e] = v; 25 val[e] = w; 26 Next[e] = Head[u]; 27 Head[u] = e; 28 } 29 }; 30 graph G; 31 #define Travel(i, u, G) for(int i = G.Head[u]; i; i = G.Next[i]) 32 //链式前向星的存图方式,Travel是遍历,这样便于我们写多图,而且挺方便的 33 bool inq[N]; 34 int dis[N]; 35 void spfa() { 36 queue<int> Q; 37 Set(dis, inf); 38 Q.push(1); dis[1] = 0; 39 while (!Q.empty() ) { 40 int now = Q.front(); Q.pop(); 41 inq[now] = false; 42 Travel(i, now, G) { 43 int v = G.to[i]; 44 if (dis[v] > dis[now] + G.val[i]) { 45 dis[v] = dis[now] + G.val[i]; 46 if (!inq[v]) { inq[v] = true; Q.push(v); } 47 } 48 } 49 } 50 } 51 //裸的spfa不解释 52 53 int dp[N]; //记忆化搜索所记忆的东西(表示到这个点最短路的条数) 54 int dfs(int u, int deep) { //deep存储从1到这个点的深度 55 if (dp[u]) return dp[u]; //如果已经到过这个点直接返回条数 56 Travel(i, u, G) { 57 int v = G.to[i]; 58 if (deep - 1 == dis[v]) //如果deep-1等于之前算出来的dis(最短路径) 59 //也就是说,当前我们所走的路径是可以走通的最短路之一 60 dp[u] = (dp[u] + dfs(v, deep-1)) % mod; //计算路径个数,并继续向下递归 61 //很简单的一个加法原理 62 } 63 return dp[u]; //最后记得返回这个值 64 } 65 66 int main (){ 67 G.init(); 68 int n = read(), m = read(); 69 while (m--) { 70 int u = read(), v = read(); 71 G.add_edge(u, v, 1); 72 G.add_edge(v, u, 1); 73 } 74 spfa(); 75 dp[1] = 1; 76 For (i, 1, n) 77 dp[i] = dfs(i, dis[i]); 78 //我们从每一个点向起点走回去,所以一开始的深度是当前这个点的最短路 79 //这样可以解释之前为什么是deep-1了 80 For (i, 1, n) 81 printf ("%d\n", dp[i]); 82 //最后输出结果 83 }