最短路计数
最短路非常熟悉,但是最短路数量怎么计算呢?
设一个计数数组sum[];
以 dij 算法为例,当 p—>q 时,如果是可以更新最短路,那么 sum[q]=sum[p];
如果不可以更新最短路,那么如果 dis[p]+edge[i].w==dis[q] ,说明 p 到 q 也是最短路,sum[q]+=sum[p] ;
模板题:洛谷·P1608 路径统计
代码:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=10100;
const int M=5000100;
const LL mod=100003;
int n,m;
struct Node{
int to,nex,w;
}edge[M*2];
int head[N],cnt,ma[N][N];
void add(int p,int q,int w){
edge[cnt].w=w,edge[cnt].to=q,edge[cnt].nex=head[p],head[p]=cnt++;
}
struct node{
int fi,se;
bool operator < (const node& rhs) const{return fi>rhs.fi;}
};
int dis[N],sum[N];
bool vis[N];
void dij(){
priority_queue<node>qu;
for(int i=1;i<=n;i++) dis[i]=2e9;
dis[1]=0;sum[1]=1;qu.push(node{0,1});
while(!qu.empty()){
node n1=qu.top();
qu.pop();
int p=n1.se;
if(vis[p]) continue;
vis[p]=true;
for(int i=head[p];~i;i=edge[i].nex){
int q=edge[i].to;
if(dis[q]>dis[p]+edge[i].w){
dis[q]=dis[p]+edge[i].w;
sum[q]=sum[p];
qu.push(node{dis[q],q});
}
else if(dis[q]==dis[p]+edge[i].w) sum[q]+=sum[p];
}
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
if(!ma[x][y]||ma[x][y]>z) add(x,y,z),ma[x][y]=z;
}
dij();
if(dis[n]==2e9) printf("No answer\n");
else printf("%d %d\n",dis[n],sum[n]);
return 0;
}
还有种情况,就是没有边权的时候(就是边权为 1 ),这种情况的最短路就是bfs一遍就可以,第一次遍历到的点,更新最短路,之后再遍历到这个点就没用了,因为第一次遍历到的点一定是最短路;所以只要标记每个点是否遍历到就行;
模板题:洛谷·P1144 最短路计数
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=1000100;
const int M=2000100;
const LL mod=100003;
int n,m;
struct Node{
int to,nex;
}edge[M*2];
int head[N],cnt;
void add(int p,int q){
edge[cnt].to=q,edge[cnt].nex=head[p],head[p]=cnt++;
}
LL ans[N],dis[N];
bool vis[N];
void bfs(){
for(int i=1;i<=n;i++) dis[i]=2e17;
dis[1]=0,ans[1]=1,vis[1]=true;
queue<int>qu;qu.push(1);
while(!qu.empty()){
int p=qu.front();qu.pop();
for(int i=head[p];~i;i=edge[i].nex){
int q=edge[i].to;
if(!vis[q]){
vis[q]=true,dis[q]=dis[p]+1;
qu.push(q);
}
if(dis[q]==dis[p]+1){
ans[q]+=ans[p];
ans[q]%=mod;
}
}
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
bfs();
for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);
return 0;
}