• CF1100E Andrew and Taxi 题解


    Description

    洛谷传送门

    Solution

    看到最大值最小这样的字眼,自然想到二分答案

    我们二分所选边权的最大权值,那么比这个值大的边都不能反向,小于等于它的边都可以选择反向。

    设当前二分到的权值为 (mid),我们不用去管小于等于 (mid) 的边(总有方法让它形成不了环),所以我们把大于 (mid) 的边全都加进去,利用拓扑排序来判断是否有负环。

    具体方法:把进队的点的个数统计出来为 (sum),判断是否等于 (n)

    • (sum < n),有环。

    • (sum = n),无环。

    符合条件的情况下我们就该找哪些边需要反向了。

    由于题目中并没有最小化反向边的数量之类的要求,所以我们可以把所有会造成环的边全部反向。

    那么有哪些边会形成环呢?

    还是拓扑排序,当我们对大于 (mid) 的边所形成的图进行拓扑排序时,记录一下它在拓扑序中的位置,即拓扑序。

    假设有 (x)(y) 两点,且拓扑序 (dfn_y < dfn_x),此时如果有一条从 (x) 连到 (y) 的边,那么这条边就会形成负环,就要给它反向。

    所以在合法的 (mid) 下遍历一遍所有的边,判一下拓扑序即可,注意边权要小于等于 (mid)

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cstring>
    #include <queue>
    
    using namespace std;
    
    const int N = 1e5 + 10;
    struct node{
        int u, v, w, nxt;
    }edge[N];
    int head[N], tot;
    int n, m, tim;
    bool vis[N], t[N];
    int in[N], dfn[N];
    int ans[N], cnt;
    
    inline void add(int x, int y, int z){
        edge[++tot] = (node){x, y, z, head[x]};
        head[x] = tot;
    }
    
    inline int topo(int now){
        int sum = 0;
        queue <int> q;
        for(int i = 1; i <= n; ++i)
            if(!in[i]) q.push(i);
        while(!q.empty()){
            int x = q.front();
            q.pop();
            sum++, dfn[x] = ++tim;
            for(int i = head[x]; i; i = edge[i].nxt){
                int y = edge[i].v;
                if(edge[i].w <= now) continue;
                if(!(--in[y])) q.push(y);
            }
        }
        return sum >= n;
    }
    
    inline bool check(int now){
        memset(in, 0, sizeof(in));
        memset(dfn, 0, sizeof(dfn));
        tim = 0;
        for(int i = 1; i <= m; ++i)
            if(edge[i].w > now) in[edge[i].v]++;
        if(!topo(now)) return 0;
        cnt = 0;
        for(int i = 1; i <= n; ++i)
            if(!dfn[i]) dfn[i] = ++tim;
        for(int i = 1; i <= m; ++i){
            int u = edge[i].u, v = edge[i].v;
            if(edge[i].w <= now && dfn[u] > dfn[v])
                ans[++cnt] = i;
        }
        return 1;
    }
    
    int main(){
        int l = 0, r = 0, maxs = 0;
        scanf("%d%d", &n, &m);
        for(int i = 1, u, v, w; i <= m; ++i){
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w);
            r = max(r, w);
        }
        while(l <= r){
            int mid = (l + r) >> 1;
            if(check(mid)) maxs = mid, r = mid - 1;
            else l = mid + 1;
        }
        printf("%d %d
    ", maxs, cnt);
        sort(ans + 1, ans + 1 + cnt);
        for(int i = 1; i <= cnt; ++i)
            printf("%d ", ans[i]);
        puts("");
        return 0;
    }
    

    End

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15496715.html

  • 相关阅读:
    centos下安装mycat
    centos下安装MySQL5.7
    centos下yum安装wget失败
    开心消消乐刷金币
    myBatis获取批量插入数据的主键id
    nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
    Mac下安装JDK 6
    VI下删除所有内容
    Mac下lombok无法安装到eclipse mars
    WEB-INF目录下的文件访问权限
  • 原文地址:https://www.cnblogs.com/xixike/p/15496715.html
Copyright © 2020-2023  润新知