#最短路 #广度优先搜索 ## 题目大意 给定一个 $n$ 个点 $m$ 条边的有向图,对于每一条边都可以赋 $[1,k]$ 范围内的权值,请问怎样赋值才能使 $1$ 到任意点的最短路径都是唯一的? ## 思路 首先,我们可以假设所有的边权都是 $1$,然后开始跑 dijkstra。如果每一条最短路径都是唯一的,那么最后的边权都赋为 $1$ 就行了。但要是不唯一呢? 很简单,因为 dijkstra 是根据向上的拓扑序来求解的,第一次遇到的点一定是最优的。如果我们发现后面的跟前面一样优,我们就在边权上面加上 $1$,这样子这条路径就不是最优的了。 最后我们判断如果有边权超过了 $k$,那么就代表无解,否则输出即可。注意这题虽然答案有可能边权有不为 $1$ 的,但是在求解的过程中每一条边只会遍历一次,而且额外增加了权值的边也不可能成为最短路径的一部分,所以不需要使用优先队列,只需要使用普通的队列即可。 ## 代码 ```cpp #include <iostream> #include <algorithm> #include <vector> #include <queue> using namespace std; const int kMaxN = 3e5 + 5; struct Edge { int to, id; }; int d[kMaxN], f[kMaxN], a[kMaxN], t, n, m, k; vector<Edge> e[kMaxN]; queue<int> q; bool dijkstra(int s) { fill(a + 1, a + m + 1, 1); fill(d + 1, d + n + 1, 1e9); fill(f + 1, f + n + 1, 0); for (q.push(s), d[s] = 0; q.size(); q.pop()) { auto t = q.front(); if (f[t]) { continue; } f[t] = 1; for (auto i : e[t]) { if (d[t] + 1 < d[i.to]) { d[i.to] = d[t] + 1; q.push(i.to); } else if (d[t] + 1 == d[i.to]){ a[i.id]++; } } } return *max_element(a + 1, a + m + 1) <= k; } int main() { for (cin >> t; t; t--) { cin >> n >> m >> k; fill(e + 1, e + n + 1, vector<Edge>()); for (int i = 1, u, v; i <= m; i++) { cin >> u >> v; e[u].push_back({v, i}); } if (dijkstra(1)) { cout << "Yes\n"; for (int i = 1; i <= m; i++) { cout << a[i] << (i == m ? '\n' : ' '); } } else { cout << "No\n"; } } return 0; } ``` ```