• AcWing1134最短路计数(spfa)


    题目地址https://www.acwing.com/problem/content/1136/

    题目描述

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

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

    输入格式

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

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

    输出格式

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

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

    数据范围

    1N1e5
    1M2e5

    题解:最短路问题最常见的是求最短路的权值,这道题让求的是最短路的条数。对于这类问题,也有很多的求解方法。

    我们可以求出最短路的一个拓扑图,首先利用dijsktra求出所有点,不过这里求的是,如果结点j的最短路是结点i,那么就存储下i是j的前驱,一个结点可能会有多条前驱,需要全部记下来,那么这样存储的就是一个新的无环的拓扑图,然后直接从源点s进行bfs就可以了,对于从队列中出来的结点,出来几次,那么到该结点的最短路就有几条。

    当然,上面的这个方法,首先需要保证不存在负圈,并且也不能存在权值为0的环。

    另一个办法就是利用spfa的松弛操作。如果队列当前拿出的结点为now,那么遍历now的每条边,如果边的另一个结点为v;dis[v]<=dis[now],那么结点v不能更新v,就忽略;dis[v]==dis[now]+1,那么这条路也是当前(注意这里不一定是全局)最短路,让num[v]+=num[now](num[i]表示当前到结点i的最短路的条数);dis[v]>dis[now]+1,那么结点v的最短路就会被更新,让num[v]=num[now]即可。

    AC代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=1e5+10,M=2e5+10,mod=1e5+3;
    typedef pair<int,int> PII;
    struct node{
        int from,to,next;
    }edge[M*2];
    int head[N],cnt,dis[N],num[N];
    int n,m;
    
    void addedge(int u,int v){
        cnt++;
        edge[cnt].from=u;
        edge[cnt].to=v;
        edge[cnt].next=head[u];
        head[u]=cnt;
    }
    
    void spfa(int s){
        int st[N]={0};
        dis[1]=0;
        num[s]=1;
        queue<int>q;
        q.push(s);
        st[s]=1;
        while(!q.empty()){
            int now=q.front();q.pop();
            st[now]=0;
            for(int i=head[now];~i;i=edge[i].next){
                if(dis[edge[i].to]<=dis[now]) continue;
                if(dis[edge[i].to]==dis[now]+1) num[edge[i].to]+=num[now];
                else num[edge[i].to]=num[now];
                num[edge[i].to]%=mod;
                dis[edge[i].to]=dis[now]+1;
                if(st[edge[i].to]) continue;
                q.push(edge[i].to);
                st[edge[i].to]=1;
            }
        }
    }
    
    int main(){
        memset(head,-1,sizeof(head));
        memset(num,0,sizeof(num));
        memset(dis,0x3f,sizeof(dis));
        cin>>n>>m;
        for(int i=1,u,v;i<=m;i++){
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        spfa(1);
        for(int i=1;i<=n;i++) cout<<num[i]<<endl;
        return 0;
    }

    写于:2020/9/10 15:52


    作者:孙建钊
    出处:http://www.cnblogs.com/sunjianzhao/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    移动端前端开发模型
    swift中高阶函数map、flatMap、filter、reduce
    函数式编程-构建
    Swift 4.0:访问级别(访问控制)
    swift内存管理
    swift where 的作用
    Swift 中的协议
    swift语言点评二十一-协议
    swift语言点评二十-扩展
    swift 20
  • 原文地址:https://www.cnblogs.com/sunjianzhao/p/13646188.html
Copyright © 2020-2023  润新知