单源最短路——最短路计数

最短路计数

给出一个 N 个顶点 M 条边的无向无权图,顶点编号为 1 到 N。

问从顶点 1 开始,到其他每个点的最短路有几条。

输入格式
第一行包含 2 个正整数 N,M,为图的顶点数与边数。

接下来 M 行,每行两个正整数 x,y,表示有一条顶点 x 连向顶点 y 的边,请注意可能有自环与重边。

输出格式
输出 N 行,每行一个非负整数,第 i 行输出从顶点 1 到顶点 i 有多少条不同的最短路,由于答案有可能会很大,你只需要输出对 100003 取模后的结果即可。

如果无法到达顶点 i 则输出 0。

数据范围
1 ≤ N ≤ 1 0 5 1≤N≤10^5 1N105,
1 ≤ M ≤ 2 × 1 0 5 1≤M≤2×10^5 1M2×105
输入样例:
5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5
输出样例:
1
1
1
2
4

题解:

我们通常的做法就是可以先求出到i点的最短路径的长度,然后再跑一遍最短路树上的路径如果符合则条数加1,但是因为做了比较多的图的题了所以可以知道我们一般分析图的题的是和我们可以结合DP来进行分析,这道题我们如果用DP的思想来做的话就是dp[cnt],最短路为cnt的路径的条数,但是我们也知道DP必须满足拓扑序才能做。但是我们图论不一定满足拓扑序。但是在最短路中我们可以把他看成最短路树,树显然满足拓扑序的。我们在在解决的时候bfs和地杰斯特拉都是满足拓扑序的。但是spfa是不满足的,所以我们可以用地杰斯特拉或者bfs在最短路树上面做这道题。

#include
using namespace std;
const int mod=100003,N=1e6+7;
int head[N],ne[N],e[N],cnt,dis[N],con[N],vis[N];
void add(int a,int b){
     
    ne[cnt]=head[a],e[cnt]=b,head[a]=cnt++;
}
void bfs()
{
     
    memset(dis,0x3f3f3f3f,sizeof dis);
    con[1]=1;
    dis[1]=0;
    queue<int> q;
    q.push(1);
    while(!q.empty()){
     
        int u=q.front(); q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];i!=-1;i=ne[i]){
     
            int j=e[i];
            if(dis[j]>dis[u]+1){
     
                dis[j]=dis[u]+1;
                con[j]=con[u];
                q.push(j);
            }else if(dis[j]==dis[u]+1){
     
                con[j]=(con[j]+con[u])%mod;
            }
        }
    }
}
int main()
{
     
    int n,m; cin>>n>>m;
    memset(head,-1,sizeof head);
    for(int i=1;i<=m;i++){
     
        int a,b; scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    bfs();
    for(int i=1;i<=n;i++) printf("%d\n",con[i]);
}

你可能感兴趣的:(图论)