Dijkstra最短路计数

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;
}
  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值