Graph 图论
Dijkstra最短路计数
我们最常用的dijkstra是来算单源最短路径,也就是最短路径的长度,如果我们要计算最短路的条数呢?我们只需要在dijkstra算法上稍加更改即可。
例如我们a->b->c
的路径长度是x,a->d->c
的路径长度也是x,所以这两条路径到达c点的距离相等,我们可以很直观的直到到达c的最短路的条数是2,如果还有一条道路c->e
,那么我们也很容易得知到达e的最短路径条数也是2
这是一个简单的例子,我们可以很直观的看出,通过这个例子我们可以想一下我们是怎样得出A->C的最短路条数是2的呢?是因为到达C的有B->C和D->C两条路,并且从起点A通过这两条路到达C的距离相等,所以在这里我们有一个简单的加和,相加的是什么呢?是到达B的最短路径条数和到达D的最短路径条数之和,在本例中到达B和D的最短路径条数都是1,那么我们又是怎样看出到达E的最短路径条数是2的呢?因为到达E的最短路径是由C到达E得到的,而到达C的最短路径条数是2,所以通过C到达E的最短路径条数也是2,通过上述例子的总结归纳,我们得到了两个式子:
如果当前可以更新最短路径,那么到达该点的最短路径条数就是通过更新他的点的最短路径条数在本例中是
dp[e] = dp[c];
if(dist[a]>dist[b]+cost[b][a]{
dist[a] = dist[b]+cost[b][a]; dp[a] = dp[b];
}
如果当前到达该点的最短路径与另一条到达该点的最短路径相同,在本例中是我们已经有了A->B->C这条路径,然后我们走到A->D->C这条路,那么
dp[c] += dp[d];
也就是再加上这条路径带来的最短路径条数:
if(dist[a] == dist[b] + cost[b][a]{
dp[a] += dp[b];
}
总上所述,我们只需要在原有的基础上多加一次两条路径相等的判断即可,我们以本题为例(不用堆优化会有两个点超时)
(dijkstra邻接表存储)
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int n,m;
int dp[1000005];
int dist[1000005];
int vis[1000005];
vector<int>map[1000005];
void dijkstra(int node){
for(int i=0;i<map[node].size();i++){
int to = map[node][i];
if(dist[to] > dist[node] + 1){
dist[to] = dist[node] + 1;
dp[to] = dp[node];
}
else if(dist[to] == dist[node] + 1){
dp[to] += dp[node];
dp[to] %= 100003;
}
}
int mini = -1;
int Min = 0x7f7f7f7f;
for(int i=1;i<=n;i++){
if(vis[i]==0 && dist[i]<Min){
mini = i;
Min = dist[i];
}
}
if(mini == -1) return ;
vis[mini] = 1;
dijkstra(mini);
}
int main(){
memset(dist,0x7f7f7f7f,sizeof(dist));
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
cin >> n >> m;
for(int i=0;i<m;i++){
int a,b;
cin >> a >> b;
map[a].push_back(b);
map[b].push_back(a);
}
dist[1] = 0;
vis[1] = 1;
dp[1] = 1;
dijkstra(1);
for(int i=1;i<=n;i++){
cout << dp[i] << endl;
}
return 0;
}
我们同样可以用堆优化进行时间复杂度的优化(dijkstra+邻接表+堆优化)
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
int vis[1000005];
int dist[1000005];
int dp[1000005];
vector<int>map[1000005];
struct edge{
int b;
int cost;
friend bool operator < (edge x,edge y){
return x.cost > y.cost;
}
};
priority_queue<edge>q;
int n,m;
void dijkstra(){
edge node;
node.b = 1;
node.cost = 0;
q.push(node);
while(!q.empty()){
node = q.top();
q.pop();
if(vis[node.b]) continue;
vis[node.b] = 1;
for(int i=0;i<map[node.b].size();i++){
int to = map[node.b][i];
if(dist[to] > dist[node.b]+1){
dist[to] = dist[node.b]+1;
dp[to] = dp[node.b];
edge p;
p.b = to;
p.cost = dist[to];
q.push(p);
}
else if(dist[to] == dist[node.b]+1){
dp[to] += dp[node.b];
dp[to] %= 100003;
}
}
}
}
int main(){
memset(dist,0x7f7f7f7f,sizeof(dist));
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
cin >> n >> m;
for(int i=0;i<m;i++){
int a,b;
cin >> a >> b;
map[a].push_back(b);
map[b].push_back(a);
}
dist[1] = 0;
dp[1] = 1;
dijkstra();
for(int i=1;i<=n;i++){
cout << dp[i] << endl;
}
return 0;
}