题目描述
给出一个N个顶点M条边的无向无权图,顶点编号为1−N。问从顶点1开始,到其他每个点的最短路有几条。
输入格式
第一行包含2个正整数N,M,为图的顶点数与边数。
接下来M行,每行2个正整数yx,y,表示有一条顶点x连向顶点y的边,请注意可能有自环与重边。
输出格式
共N行,每行一个非负整数,第ii行输出从顶点1到顶点i有多少条不同的最短路,由于答案有可能会很大,你只需要输出ans mod100003后的结果即可。如果无法到达顶点i则输出0。
输入输出样例
输入 #1
5 7 1 2 1 3 2 4 3 4 2 3 4 5 4 5
输出 #1
1 1 1 2 4
说明/提示
1到5的最短路有4条,分别为2条1−2−4−5和2条1−3−4−5(由于4−5的边有2条)。
对于20%的数据,N≤100;
对于60%的数据,N≤1000;
对于100%的数据,N<=1000000,M<=2000000。
题目来源洛谷P1144
既然是最短路计数肯定先求最短路d[i]
然后BFS 扫描到每一个点u 如果其能到达的点为v 且d[v]==d[u]+1则记录答案
注意不能重复经过同样的边而不是点(重边不算),
因为如果记录点无论这个点i可以被多少个点搜到都只能搜一次,不符合加法原理
同时自环不需要考虑
还有一点注意 用ans[i]表示第i个点最终的答案 设点j能到点i 则如果满足
d[i]==d[j]+1 ans[i]+=ans[j]而不是加1(因为从点1走到点j已经有ans[j]种,乘法原理可以得到答案)
上代码
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define mod 100003 using namespace std; int n,m,head[1000050],num,vst[4000050],book[4000050],d[1000050],ans[1000050]; priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q; queue<int> q1; struct edge { int u,v,nxt; }e[4000050]; void add(int u,int v) { e[num].u=u;e[num].v=v; e[num].nxt=head[u];head[u]=num++; } int main() { memset(head,-1,sizeof head); memset(d,127,sizeof d); scanf("%d%d",&n,&m); int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); if(x!=y) { add(x,y); add(y,x); } } d[1]=0; q.push(make_pair(d[1],1)); while(!q.empty()) { int x=q.top().second; q.pop(); if(vst[x])continue; vst[x]=1; for(int st=head[x];~st;st=e[st].nxt) { int y=e[st].v; if(d[x]+1<d[y]) { d[y]=d[x]+1; q.push(make_pair(d[y],y)); } } }//dijkstra+heap求最短路 ans[1]=1; q1.push(1);//标记点1只有一条路能到自己(停在原地) while(!q1.empty()) { int x=q1.front(); q1.pop(); for(int st=head[x];~st;st=e[st].nxt) { if(book[st])continue; book[st]=book[st^1]=1;//记录该边已经走过,注意是双向边 int y=e[st].v; if(d[y]==d[x]+1) ans[y]=(ans[y]+ans[x]%mod)%mod;//记得取模!!占40分 q1.push(y); } } for(int i=1;i<=n;i++)printf("%d ",ans[i]%mod); return 0; }