Codeforces Round #791(Div 2)——D
D
题意:
给定一个有向图,每个点有自己的点权,求一条长度为K的路径使得路径上的最大点权最小,输出该条路径上的最大点权。
思路:(二分+拓扑排序)
最小值最大的题考虑二分解决。
我们每次二分答案为mx,以此判断有没有某条路径的最大值为mx且长度为k。因为我们要保证二分出来的mx是该条路径上最大的点权,所以所有大于mx的点我们都要舍弃。
其次如果路径中含环那必然是可以的,如果不含吗,就需要判断是否存在长度为k,最大值为mx的路径
举个例子:
最初的图 
当k == 4时,当我们判断mid = 4(既mx=4)时,则存在这样一条路径

chick返回true
判断环的时候可以通过拓扑排序来判断
在chick的时候需要注意的是,因为我们每次取的是小于等于mx的点,所以每次每个点的入度都不同,都需要重新统计
1 const int N = 2e5 + 10,INF = 0x3f3f3f3f3f;
2 int n, m, k, w[N];
3 vector<int> g[N];
4 int vis[N], deg[N], deep[N];/*vis判断是否小于等于mx,deg统计入度,deep统计路径长度*/
5 vector<pair<int, int> >e;
6
7 bool chick(int mx) {
8 for (int i = 1; i <= n; ++i) vis[i] = 0, deg[i] = 0, deep[i] = -INF;
9 for (int i = 1; i <= n; ++i) {
10 if (w[i] <= mx)vis[i] = 1;
11 }
12 for (auto it : e) {
13 if (w[it.first] <= mx && w[it.second] <= mx) {
14 deg[it.second]++;
15 }
16 }
17 queue<int> q;
18 for (int i = 1; i <= n; ++i ) {
19 if (vis[i] && !deg[i])q.push(i),deep[i] = 1;
20 }
21 while (q.size()) {
22 int u = q.front();
23 q.pop();
24 for (int s : g[u]) {
25 if (!vis[s]) continue;
26 deep[s] = max(deep[s], deep[u] + 1);
27 if (deep[s] >= k) return 1;
28 deg[s]--;
29 if (deg[s] == 0) q.push(s);
30 }
31 }
32 for (int i = 1; i <= n; ++i) {
33 if (vis[i] && deg[i] > 0)return 1;
34
35 }
36 return 0;
37 }
38
39 void solve() {
40 cin >> n >> m >> k;
41 for (int i = 1; i <= n; ++i) cin >> w[i];
42 for (int i = 1; i <= m; ++i) {
43 int x, y;
44 cin >> x >> y;
45 g[x].push_back(y);
46 e.push_back({x, y});
47 }
48 if (k == 1) {
49 cout << *max_element(w + 1, w + 1 + n) << endl;
50 return;
51 }
52 int ans = INF;
53 int l = 0, r = 1e9 + 1;
54 for (int i = 1; i <= 50; ++i) {
55 int mid = (l + r) >> 1;
56 if (chick(mid)) {
57 ans = min(ans, mid);
58 r = mid - 1;
59 } else l = mid + 1;
60 }
61 if (ans == INF) {
62 cout << -1 << endl;
63 } else cout << ans << endl;
64 }

浙公网安备 33010602011771号