洛谷Oj-P1144 最短路计数-Dijkstra + 递推

版权声明:欢迎转载 https://blog.csdn.net/suntengnb/article/details/80026671

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

typedef pair<int,int> Pair;//到源点的距离、顶点编号
priority_queue<Pair,vector<Pair>,greater<Pair> > pq;//小顶堆
struct edge
{
    int to;
    int next;
    int w;
};
edge e[2000010];
int head[1000010];
int id = 1;

int n,m;
int dis[1000010];//距离
int cnt[1000010];//cnt[i]表示从源点到顶点i的最短路的条数
void add_edge(int u,int v,int w)
{
    e[id].to = v;
    e[id].next = head[u];
    e[id].w = w;
    head[u] = id;
    id++;
}
void dijkstra(int s)//堆优化
{
    memset(dis,0x3F,sizeof(dis));//初始化
    dis[s] = 0;//初始化
    cnt[1] = 1;//递推边界
    pq.push(make_pair(dis[s],s));//将源点入堆
    while(!pq.empty())
    {
        int v = pq.top().second;
        pq.pop();
        for(int i = head[v]; i != -1; i = e[i].next)
        {
            int to = e[i].to;
            int w = e[i].w;
            if(dis[to] == dis[v] + w)//如果和当前的最短路长度相等
                cnt[to] = (cnt[to] + cnt[v]) % Mod;//则加上cnt[中转点v]
            if(dis[to] > dis[v] + w)//如果比当前的最短路还要短
            {
                dis[to] = dis[v] + w;//更新
                cnt[to] = 0;//置0
                cnt[to] = (cnt[to] + cnt[v]) % Mod;//加上cnt[中转点v]
                pq.push(make_pair(dis[to],to));//因为dis[to]被松弛了,再入堆
            }
        }
    }
    return;
}
int main()
{
    cin >> n >> m;
    memset(head,-1,sizeof(head));//初始化
    for(int i = 1; i <= m; ++i)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(a == b)//去掉自环
            continue;
        add_edge(a,b,1);
        add_edge(b,a,1);
    }
    dijkstra(1);
    for(int i = 1; i <= n; ++i)
        cout << cnt[i] << endl;
    return 0;
}

解决方法:
因为路径的长度都是1,考虑用邻接矩阵的幂次去做,逐次累乘,判断是否可达,答案为第一次可达时的 a11a12a1n 。但是看到数据规模,这个方法算是没戏了。
再就是考虑用最短路算法,比如Dijkstra去做(为了跑得快一点,加了堆优化),然后在用中转点松弛这一步上做文章,被松弛了说明要推翻之前的最短路条数,恰好相等则要加上,就这样递推。对于每一个中转点来说,它到源点的路径长度已经是最短的了,不会再被松弛,最短路的条数也确定了。

猜你喜欢

转载自blog.csdn.net/suntengnb/article/details/80026671