【算法】最短路计数(计算最短路的数量)

题目 

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

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

输入格式

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

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

输出格式

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

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

数据范围

1≤ N ≤ 10^5
1 ≤ M ≤ 2×105

思路

由于该图为无向无权图,因此最短路为经过点最少的路径。 

样例:
5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5

 根据样例,我们得到下面这张图。

【算法】最短路计数(计算最短路的数量)_第1张图片

         dist[]数组储存走到当前点,最少经过的点数。

        1、如果在bfs过程中,后面的点 i 比他的前驱 j 的点数+1还要大,则说明当前dist[i]中储存的不是当前点 i 所经过的最小点数。更新点 i ,dist[ i ] = dist[ j ] + 1; cnt[ i ] = cnt[ j ]。

        2、如果在bfs过程中,后面的点 i 与他的前驱 j 的点数+1相等,则说明从点 j 到达点 i 也是最短路。更新点 i , cnt[ i ] = cnt[ j ] + cnt[ i ]。(注意取模)

        3、如果在bfs过程中,后面的点 i 比他的前驱 j 的点数+1要小,则不进行任何操作。

代码

#include
using namespace std;
const int N = 1e5 + 10,M = 4e5 + 10,MOD = 100003;
int n,m;
int h[N],e[M],ne[M],idx;
int dist[N],cnt[N];// cnt中储存最短路的个数
queue q;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}

void bfs()
{
    memset(dist,0x3f,sizeof(dist));
    dist[1] = 0;
    cnt[1] = 1;
    q.push(1);
    while(q.size())
    {
        int t = q.front();
        q.pop();
        for(int i = h[t]; ~i ; i = ne[i])
        {
            int j = e[i];
            if(dist[j] > dist[t] + 1)
            {
                dist[j] = dist[t] + 1;
                cnt[j] = cnt[t];
                q.push(j);
            }
            else if(dist[j] == dist[t] + 1)
            {
                cnt[j] = (cnt[j] + cnt[t]) % MOD;
            }
        }
    }
}

int main()
{
    memset(h,-1,sizeof(h));
    cin >> n >> m;
    int a,b;
    while(m --)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    bfs();
    for(int i = 1; i <= n; i ++)
    {
        cout << cnt[i] << endl;
    }
    return 0;
}

你可能感兴趣的:(算法,算法,图论,bfs,最短路问题)