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 }

 

posted @ 2017-07-29 10:35  zjp_shadow  阅读(283)  评论(0编辑  收藏  举报