P1144 最短路计数

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\n",js[i]);
    }
    return 0;
}

 

posted @ 2020-07-14 11:17  徐明拯  阅读(126)  评论(0编辑  收藏  举报