https://www.luogu.com.cn/problem/P1144
思路:
刚看到看到这个题其实我的思路还挺清晰的,因为没有边权,所以我可以设所有边权都为1,然后跑Dijkstra不断更新最短路长度。在更新过程中,如果找到了一条跟最短路长度相同的路径,那么我的最短路路径条数就加上可以跑到起点的路径条数。如果找到了一条更短的路径,那么很明显之前记录的路径条数都是不对的,那么直接覆盖。实际上这就是正解。但是当我看到可能会有自环和重边之后,我慌了。作为刚刚熟悉三个最短路算法,还没刷过题的图论蒟蒻来说,我不知道这句话要有什么别的操作,所以我迟迟不敢动手写,而且到最后也不知道该怎么搞这两个东西。最后在这句话加绿题的恐吓下,我遗憾离场,查看了题解,然后想把我自己头拧下来。认真思考一下其实不难发现,这句话有没有其实都一样。因为我要找最短路,所以自环肯定不会跑,那么对结果没有影响。重边我根本不用特判,我直接像正常一样存图,然后遍历就行了。所以还是要相信自己。
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; int n,m,tot; const int mod=100003,N=1000005,M=2000005; int head[N],Next[M],edge[M],ver[M],dis[N],js[N];//js[i]表示从1到i的最短路的条数 priority_queue< pair<int,int> >q; inline void add(int x,int y,int z){ ver[++tot]=y; edge[tot]=z; Next[tot]=head[x]; head[x]=tot; }//链式前向星存图 void dijkstra(){ memset(dis,0x3f,sizeof(dis)); dis[1]=0; js[1]=1; q.push(make_pair(0,1)); while(!q.empty()){ int u=q.top().second,d=dis[u]; q.pop(); for(int i=head[u];i;i=Next[i]){//遍历 int v=ver[i],z=edge[i]; if(d+z==dis[v]){ js[v]=(js[u]+js[v])%mod;//如果跟最短路一样长,那么也就是说找到了另一条最短路,那么就可以更新最短路的条数了 } if(dis[v]>dis[u]+z){ dis[v]=dis[u]+z; js[v]=js[u];//如果发现了一条更短的,直接将之前记录的最短路条数覆盖掉 q.push(make_pair(-dis[v],v)); } } } } int main() { scanf("%d%d",&n,&m); for(int i=1,x,y;i<=m;i++){ scanf("%d%d",&x,&y); add(x,y,1); add(y,x,1);//无向图要建两遍 } dijkstra(); for(int i=1;i<=n;i++){ printf("%d ",js[i]); } return 0; }