首先肯定要把边拆点, 就变成了最短路问题, 最短路相同的字典序要求最小。
所以我们先bfs找出最短路图建边, 然后dfs把字典序从小到达枚举去更新点,
这样就是字典序最小的。
其实可以一遍bfs就完成的。
#include<bits/stdc++.h> #define fi first #define se second #define mk make_pair #define PII pair<int, int> using namespace std; const int N = (int)1e6 + 7; const int mod = (int)1e9 + 7; int n, m, tot; int d[N], ans[N]; vector<PII> G[N]; vector<int> G2[N][10]; vector<int> V; void solve(int u, int v, int x) { V.clear(); for(int i = x; i; i /= 10) { V.push_back(i % 10); } reverse(V.begin(), V.end()); int cur = u; for(int i = 0; i < V.size(); i++) { if(i == (int)V.size() - 1) { G[cur].push_back(mk(V[i], v)); } else { tot++; G[cur].push_back(mk(V[i], tot)); cur = tot; } } cur = v; for(int i = 0; i < V.size(); i++) { if(i == (int)V.size() - 1) { G[cur].push_back(mk(V[i], u)); } else { tot++; G[cur].push_back(mk(V[i], tot)); cur = tot; } } } void dfs(vector<int> &P) { vector<int> V; for(int i = 0; i <= 9; i++) { V.clear(); for(auto &u : P) { for(auto &v : G2[u][i]) { if(~ans[v]) continue; ans[v] = (1LL * ans[u] * 10 + i) % mod; V.push_back(v); } } if(V.size()) dfs(V); } } int main() { scanf("%d%d", &n, &m); tot = n; for(int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); solve(u, v, i); } for(int i = 1; i <= tot; i++) { d[i] = -1; ans[i] = -1; } d[1] = 0; queue<int> que; que.push(1); while(!que.empty()) { int u = que.front(); que.pop(); for(auto &e : G[u]) { int v = e.se, w = e.fi; if(d[v] == -1) { d[v] = d[u] + 1; G2[u][w].push_back(v); que.push(v); } else if(d[u] + 1 == d[v]) { G2[u][w].push_back(v); } } } ans[1] = 0; vector<int> V; V.push_back(1); dfs(V); for(int i = 2; i <= n; i++) { printf("%d ", ans[i]); } return 0; } /* */