• 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 }
  • 相关阅读:
    c++ 启发式搜索解决八数码问题
    基于linux或windows的c/s的循环服务器求一元二次方程的根
    基于linux或windows平台上的c/s简单通信
    第七章总结
    第六章总结
    第五章总结
    第四章总结
    第一章总结
    第三章总结
    第二章总结
  • 原文地址:https://www.cnblogs.com/scaulok/p/10288502.html
Copyright © 2020-2023  润新知