洛谷P1144 最短路计数
做了一下午终于A了这题,谈谈心得。
这题主要思路是这样的,在SPFA中加入计数操作,如果这个点的最短路可以更新但还未被更新既
if(dis[v]>dis[u]+1)
那么很显然,目前我们可以知道的可到达这个点的最短路就是通过先到达上个点再走当前边的方式,易推得代码
ans[v]=ans[u];
当一个点不能被当前点更新时,判断如果这个点的距离等于当前点距离+1的话,那么就如同上面的情况,可到达这个点的最短路有一种是通过先到达上个点再走当前边的方式得到的,那么我们就把这个情况加上,可得代码
ans[v]+=ans[u]
将这个计数方法放到SPFA的模板中就可以ac本题
几个注意事项
1.边加边膜 防止爆int
2.ans[1]=1。因为很显然,从一到一的最短路有且只有一条、
3.存双向边
4.自环和重边并不会对本题造成影响
贴上ac代码
#include<bits/stdc++.h> using namespace std; const int mod=100003; const int Maxn=1000010; const int MAxn=5000010; const int MAXn=0x7fffffff; struct st{ int to,nxt; }edge[MAxn]; int n,m,cnt=0,dis[Maxn]; int head[Maxn],vis[Maxn],ans[Maxn]; inline void add_edge(int u,int v){ edge[++cnt].nxt=head[u]; edge[cnt].to=v; head[u]=cnt; } inline void SPFA(int s){ for(int i=1;i<=n;++i) dis[i]=MAXn; dis[s]=0; vis[s]=1; queue<int> Q; Q.push(s); while(!Q.empty()){ int u=Q.front(); Q.pop();vis[u]=0; for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(dis[v]>dis[u]+1){ dis[v]=dis[u]+1; ans[v]=ans[u]; ans[v]%=mod; if(!vis[v]){ vis[v]=1; Q.push(v); } } else if(dis[v]==dis[u]+1){ ans[v]+=ans[u]; ans[v]%=mod; } } } } int main(){ ans[1]=1; memset(vis,0,sizeof(vis)); scanf("%d %d",&n,&m); for(int i=1;i<=m;++i){ int x,y; scanf("%d %d",&x,&y); add_edge(x,y); add_edge(y,x); } SPFA(1); for(int i=1;i<=n;++i) printf("%d\n",ans[i]); return 0; }
附ac时间
裂屏推荐本人博客,希望互相学习