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
#include
#include
#include
#define mod 100003
using namespace std;
int n,m,head[1000050],num,vst[4000050],book[4000050],d[1000050],ans[1000050];
priority_queueint,int>,vectorint,int> >,greaterint,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\n",ans[i]%mod);
    return 0;
}

 

你可能感兴趣的:(2019暑假集训 最短路计数)