Codeforces Round #532 (Div. 2) E. Andrew and Taxi(二分+拓扑排序)

题目链接:https://codeforces.com/contest/1100/problem/E

题意:给出 n 个点 m 条边的有向图,要翻转一些边,使得有向图中不存在环,问翻转的边中最大权值最小是多少。

题解:首先要二分权值,假设当前最大权值是 w,那么大于 w 的边一定不能翻转,所以大于 w 所组成的有向图不能有环,而剩下小于等于 w 的边一定可以构造出一个没有环的图(因为如果一条边正反插入都形成环的话,那么图里之前已经有环了),构造方法是把大于 w 的边跑拓扑序,然后小于等于 w 的边序号小的连向序号大的。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define mst(a,b) memset((a),(b),sizeof(a))
 6 #define mp(a,b) make_pair(a,b)
 7 #define pi acos(-1)
 8 #define pii pair<int,int>
 9 #define pb push_back
10 #define lowbit(x) ((x)&(-x))
11 const int INF = 0x3f3f3f3f;
12 const double eps = 1e-6;
13 const int maxn = 1e5 + 10;
14 const int maxm = 1e6 + 10;
15 const ll mod =  1e9 + 7;
16 
17 int n,m;
18 
19 struct edge {
20     int from,to,w;
21 }e[maxn];
22 
23 vector<int>vec[maxn];
24 int vis[maxn];
25 bool flag;
26 
27 void dfs(int u,int mid) {
28     vis[u] = 1;
29     for(int i = 0; i < vec[u].size(); i++) {
30         int x = vec[u][i];
31         if(e[x].w <= mid) continue;
32         if(vis[e[x].to] == 1) {
33             flag = false;
34             continue;
35         } else if(vis[e[x].to] == 2) continue;
36         dfs(e[x].to,mid);
37     }
38     vis[u] = 2;
39 }
40 
41 bool check(int mid) {
42     mst(vis, 0);
43     flag = true;
44     for(int i = 1; i <= n; i++) {
45         if(vis[i] == 0) dfs(i,mid);
46     }
47     return flag;
48 }
49 
50 vector<int>out;
51 int top[maxn], du[maxn];
52 
53 int main() {
54 #ifdef local
55     freopen("data.txt", "r", stdin);
56 //    freopen("data.txt", "w", stdout);
57 #endif
58     scanf("%d%d",&n,&m);
59     for(int i = 1; i <= m; i++) {
60         scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w);
61         vec[e[i].from].push_back(i);
62     }
63     int l = 0, r = 1e9, ans = 0;
64     while(l <= r) {
65         int mid = (l + r) >> 1;
66         if(check(mid)) ans = mid, r = mid - 1;
67         else l = mid + 1;
68     }
69     for(int i = 1; i <= m; i++)
70         if(e[i].w > ans) du[e[i].to]++;
71     queue<int>q;
72     int tot = 0;
73     for(int i = 1; i <= n; i++)
74         if(du[i] == 0) q.push(i);
75     while(!q.empty()) {
76         int u = q.front();
77         q.pop();
78         top[u] = ++tot;
79         for(int i = 0; i < vec[u].size(); i++) {
80             int v = vec[u][i];
81             if(e[v].w <= ans) continue;
82             du[e[v].to]--;
83             if(du[e[v].to] == 0) q.push(e[v].to);
84         }
85     }
86     for(int i = 1; i <= m; i++)
87         if(e[i].w <= ans && top[e[i].from] > top[e[i].to]) out.push_back(i);
88     printf("%d %d
",ans,out.size());
89     for(int i = 0; i < out.size(); i++) printf("%d ",out[i]);
90     return 0;
91 }
原文地址:https://www.cnblogs.com/scaulok/p/10288502.html