【图论】C_P1144_最短路计数(路径计数)

一、题目描述

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

输入格式

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

输出格式

  • 共N行,每行一个非负整数,第ii行输出从顶点11到顶点ii有多少条不同的最短路,由于答案有可能会很大,你只需要输出 ans mod 100003 后的结果即可。如果无法到达顶点i则输出0。

输入输出

5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5
输出
1
1
1
2
4
  • 对于20%的数据,N≤100;
  • 对于60%的数据,N≤1000;
  • 对于100%的数据,N<=1000000,M<=2000000

二、题解

方法一:spfa

思路

  • 题中没有说边权是多少,所以我们可以认为设定每个结点之间的边权 w 为一个常数,进而简化问题。
  • 设定一个 int[] cnt 来记录到达每个点的最短路的个数。
  • 如果 dist[to] > dist[u] + w,意味着从 1 到 to 的最短路的比 1 到 v 的长,所以此时 cnt[to] 的计数是不算入内的,又因为 to 可看做是 v 的子节点,所以从 1 到 to 的计数还是 cnt[v]

Q&A:

  • Q1:图中可能存在自环,怎么证明自环不会对结果造成影响?
    A1:如果存在自环,那么也就只能到自己那里了,其他店到不了,自然为 0。
  • Q2:图中可能存在重边,怎么证明重边不会对结果造成影响?
    A2:无向图是一种特殊有向图。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static int V, E, D;
	static Edge[] edges;
	static int[] dist, head;
	static boolean[] vis, inq;
	static int tot;
	static int INF = 0x3f3f3f3f;
	static int maxv = 1000000 + 50, maxe = 2000000 + 50; 
	static int[] cnt;
	
	static class Edge {
        int to, w, next;
        Edge() {}
    } 
	static void addEdge(int u, int v, int w) {
		edges[++tot] = new Edge();
		edges[tot].to = v;
		edges[tot].w = w;
		edges[tot].next = head[u];
		head[u] = tot;
	}
	static void spfa(int S) {
		Arrays.fill(dist, INF);
		dist[S] = 0;
		Queue<Integer> q = new ArrayDeque<>();
		q.add(S);
		inq[S] = true;
		cnt[S] = 1;
		while (!q.isEmpty()) {
			int v = q.poll();
			inq[v] = false;
			for (int i = head[v]; i != 0; i = edges[i].next) {
				int to = edges[i].to, w = edges[i].w;
				if (dist[to] > dist[v] + w) {
					dist[to] = dist[v] + w;
					cnt[to] = cnt[v];
					if (!inq[to]) {
						q.add(to);
						inq[to] = true;
					}
				} else if (dist[to] == dist[v] + w) {
					cnt[to] = (cnt[to] + cnt[v]) % 100003;
				}
			}
		}
	}
    public static void main(String[] args) throws IOException {  
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
        
		while (sc.hasNext()) {
			int V = sc.nextInt();   
			int E = sc.nextInt();   
			dist = new int[maxv];
			edges = new Edge[2*maxe+50];
			inq = new boolean[maxv];
			head = new int[maxv];
			cnt = new int[maxv];
			
			for (int i = 0; i < E; i++) {
				int a = sc.nextInt();
				int b = sc.nextInt();
				addEdge(a, b, 1);
				addEdge(b, a, 1);
			}
			spfa(1);
			for (int i = 1; i <= V; i++) {
				System.out.println(cnt[i]);
			}
		}
    }
}

复杂度分析

  • 时间复杂度: O ( k E ) O(kE) O(kE)
  • 空间复杂度: O ( . . . ) O(...) O(...)

你可能感兴趣的:(#,图论)