• 2019暑假集训 最短路计数


    题目描述

    给出一个N个顶点M条边的无向无权图,顶点编号为1N。问从顶点1开始,到其他每个点的最短路有几条。

    输入格式

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

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

    输出格式

    N行,每行一个非负整数,第ii行输出从顶点1到顶点i有多少条不同的最短路,由于答案有可能会很大,你只需要输出anmod100003后的结果即可。如果无法到达顶点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
    

    说明/提示

    15的最短路有4条,分别为2条1245和2条1345(由于45的边有2条)。

    对于20%的数据,N100;

    对于60%的数据,N1000;

    对于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;
    }
    /*====年轻人,瞎搞是出不了省一的,这就是现实====*/
  • 相关阅读:
    GIT在Linux上的安装和使用简介心得
    Android开发环境使用到工具的认识心得
    Android系统移植与驱动开发心得
    嵌入式Linux的调试技术
    硬件抽象层——HAL
    Linux代码的重用与强行卸载Linux驱动
    控制发光二极管
    详细讲解Linux驱动程序
    搭建测试环境——针对S3C6410开发板
    有了源代码,当然还需要编译喽!!
  • 原文地址:https://www.cnblogs.com/qxds/p/11387958.html
Copyright © 2020-2023  润新知