算法题(251):最短路计数

审题:
本题需要我们找到从节点1开始到其他节点的最短路径有多少条思路:
方法一:dijkstra算法+动态规划
本题的图是无向无权图,也就是说边是双向可走的,边权都是一样的我们可以记为1
由于某个节点的最短路径dist[i]等于他的有效前驱节点(最短路径走到i位置的节点)的dist值相加,所以我们需要通过搜索方法找到节点的有效前驱节点,而这种搜索方法就是dijkstra算法
状态表示:f[i]表示从起点到节点1的最短路径条数
状态转移方程:f[i] = Σf[prev]
填表顺序:按照dijkstra算法的遍历顺序进行更新
解题:
#include<iostream> #include<queue> #include<vector> #include<cstring> using namespace std; const int N = 1e6 + 10, M = 2e6 + 10, MOD = 100003; typedef pair<int, int> pii; int n, m; vector<int> edges[N]; priority_queue<pii, vector<pii>, greater<pii>> q; int dist[N],f[N]; bool st[N]; void dijkstra() {//初始化memset(dist, 0x3f, sizeof dist);memset(f, 0, sizeof f);memset(st, 0, sizeof st);q.push({ 0,1 });dist[1] = 0;//f初始化f[1] = 1;while (q.size()){auto a = q.top(); q.pop();int s = a.second; //添加判断if (st[s]) continue;st[s] = true;for (auto& e : edges[s]){if (dist[s] + 1 < dist[e])//找到e前驱更短路{dist[e] = dist[s] + 1;q.push({dist[e],e});f[e] = f[s];}//这里必须设置成if else,否则前面改成了等于,后面语句条件一定会满足了else if (dist[s] + 1 == dist[e])//找到更多同级最短路{f[e] = (f[e]+f[s])%MOD;}}}} int main() {//数据录入scanf("%d%d", &n, &m);for (int i = 1; i <= m; i++){int l, r; scanf("%d%d", &l, &r);edges[l].push_back(r);edges[r].push_back(l);}//dijkstradijkstra();//答案输出for (int i = 1; i <= n; i++){printf("%d\n", f[i]);}return 0; }关键1:数据输入输出方式
由于题目中的数据读取和输出量较大,所以为了减少时间消耗,我们采用快速输入输出方式,scanf和printf
关键2:更新时机
当进行松弛操作时,表示当前节点找到了更短的路径,直接将前驱的f值覆盖掉当前节点f值
若松弛操作显示路径相等,说明有其他的同级最短路径被找到了,累加该节点f值
关键3:答案输出要注意取模
题目中特别说明了需要取模,所以我们在进行累加的时候顺便就进行取模操作,最终输出的时候就不用再取模了
