最短路计数(dijkstra和spfa)

题意:
给定一个 n n n个点 m m m条边的无向连通图,求从 1 1 1号点到达每个点的最短路的最短路条数。
数据范围: 1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 1\leq n\leq 10^5,1\leq m\leq2\times 10^5 1n105,1m2×105

题解:
如果带负权边那么只能考虑 s p f a spfa spfa,否则使用 d i j k s t r a dijkstra dijkstra即可。
由于 s p f a spfa spfa并非按照拓扑序来更新最短路,所以为了更好地解决问题,建议统一先求一遍最短路,然后使用记忆化搜索求到达每个点的最短路条数。特别地,需要初始化到达点 1 1 1的最短路条数为 1 1 1

代码:

/*dijkstra实现*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int N = 1e5 + 10;
const int M = 4e5 + 10;
const int mod = 100003;
int n, m;
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int c) {
    
    
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
} 

struct Node {
    
    
    int id, d;
    bool operator < (const Node &A) const {
    
    
        return d > A.d;
    }
};

priority_queue<Node> q;
int dist[N], cnt[N];
bool st[N];
void dijkstra() {
    
    
    memset(st, false, n + 1);
    memset(dist, 0x3f, n + 1 << 2);
    dist[1] = 0;
    q.push({
    
    1, 0});
    
    while(!q.empty()) {
    
    
        Node t = q.top(); q.pop();
        int u = t.id;
        if(st[u]) continue;
        st[u] = true;
        
        for(int i = h[u]; ~i; i = ne[i]) {
    
    
            int v = e[i];
            if(dist[v] > dist[u] + w[i]) {
    
    
                dist[v] = dist[u] + w[i];
                q.push({
    
    v, dist[v]});
            }
        }
    }
}

int get(int v) {
    
    
    if(st[v]) return cnt[v];
    st[v] = true;
    for(int i = h[v]; ~i; i = ne[i]) {
    
    
        int u = e[i];
        if(dist[v] == dist[u] + w[i]) cnt[v] = (cnt[v] + get(u)) % mod;
    }
    return cnt[v];
} 

int main()
{
    
    
    scanf("%d%d", &n, &m);
    memset(h, -1, n + 1 << 2);
    idx = 0;
    for(int i = 1; i <= m; ++i) {
    
    
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b, 1);
        add(b, a, 1);
    }
    
    dijkstra();
    
    memset(st, false, n + 1);
    st[1] = true; cnt[1] = 1;
    for(int i = 1; i <= n; ++i) printf("%d\n", get(i));
    
    return 0;
}

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int N = 1e5 + 10;
const int M = 4e5 + 10;
const int mod = 100003;
int n, m;
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int c) {
    
    
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
} 

queue<int> q;
int dist[N], cnt[N];
bool st[N];
void spfa() {
    
    
    memset(st, false, n + 1);
    memset(dist, 0x3f, n + 1 << 2);
    dist[1] = 0;
    q.push(1);
    st[1] = true;
    
    while(!q.empty()) {
    
    
        int u = q.front(); q.pop();
        st[u] = false;
        for(int i = h[u]; ~i; i = ne[i]) {
    
    
            int v = e[i];
            if(dist[v] > dist[u] + w[i]) {
    
    
                dist[v] = dist[u] + w[i];
                if(!st[v]) q.push(v), st[v] = true;
            }
        }
    }
}

int get(int v) {
    
    
    if(st[v]) return cnt[v];
    st[v] = true;
    for(int i = h[v]; ~i; i = ne[i]) {
    
    
        int u = e[i];
        if(dist[v] == dist[u] + w[i]) cnt[v] = (cnt[v] + get(u)) % mod;
    }
    return cnt[v];
} 

int main()
{
    
    
    scanf("%d%d", &n, &m);
    memset(h, -1, n + 1 << 2);
    idx = 0;
    for(int i = 1; i <= m; ++i) {
    
    
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b, 1);
        add(b, a, 1);
    }
    
    spfa();
    
    memset(st, false, n + 1);
    st[1] = true; cnt[1] = 1;
    for(int i = 1; i <= n; ++i) printf("%d\n", get(i));
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43900869/article/details/114005501