luogu 1144 最短路計數 (堆優化Dijkstra)
阿新 • • 發佈:2018-12-02
題目描述
給出一個N個頂點M條邊的無向無權圖,頂點編號為1-N。問從頂點1開始,到其他每個點的最短路有幾條。
輸入輸出格式
輸入格式:
第一行包含2個正整數N,M為圖的頂點數與邊數。
接下來M行,每行2個正整數x,y,表示有一條頂點x連向頂點y的邊,請注意可能有自環與重邊。
輸出格式:
共N行,每行一個非負整數,第ii行輸出從頂點1到頂點i有多少條不同的最短路,由於答案有可能會很大,你只需要輸出ans mod 100003後的結果即可。如果無法到達頂點ii則輸出0。
輸入輸出樣例
輸入樣例#1:
5 7 1 2 1 3 2 4 3 4 2 3 4 5 4 5
輸出樣例#1:
1 1 1 2 4
說明
1到5的最短路有4條,分別為2條1-2-4-5和2條1-3-4-5(由於4−5的邊有2條)。
對於20%的資料,N ≤ 100;
對於60%的資料,N ≤ 1000;
對於100%的資料,N<=1000000,M<=2000000。
題目連結:https://www.luogu.org/problemnew/show/P1144
題目分析:由於用鏈式前向星存邊,對重邊無需做特殊判斷
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <map> using namespace std; int const MAXN = 1000005; int const MAXM = 2000005; int const INF = 0x3ffffff; int const MOD = 100003; int n, m, dis[MAXN], num[MAXN]; int cnt, head[MAXN]; bool vis[MAXN]; map<pair<int, int>, int> mp; map<pair<int, int>, int>:: iterator it; struct EDGE { int to, w, nxt; }e[MAXM << 1]; void Init() { cnt = 0; memset(head, -1, sizeof(head)); memset(vis, false, sizeof(vis)); } void Add(int u, int v) { e[cnt].to = v; e[cnt].w = 1; e[cnt].nxt = head[u]; head[u] = cnt++; } void HeapDijkstra(int v0) { priority_queue< pair<int, int>, vector< pair<int, int> >, greater< pair<int, int> > > q; for (int i = 1; i <= n; i++) { dis[i] = INF; } dis[v0] = 0; num[v0] = 1; q.push(make_pair(0, v0)); while (!q.empty()) { int u = q.top().second; q.pop(); if (!vis[u]) { vis[u] = true; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].to; if (dis[v] == dis[u] + e[i].w) { num[v] += num[u]; num[v] %= MOD; } else if (dis[v] > dis[u] + e[i].w) { dis[v] = dis[u] + e[i].w; q.push(make_pair(dis[v], v)); num[v] = num[u]; } } } } } int main() { Init(); scanf("%d %d", &n, &m); int u, v; for (int i = 0; i < m; i++) { scanf("%d %d", &u, &v); if (u == v) { continue; } Add(u, v); Add(v, u); } HeapDijkstra(1); for (int i = 1; i <= n; i++) { printf("%d\n", num[i] % MOD); } }