zoukankan      html  css  js  c++  java
  • CF-1100 E Andrew and Taxi

    CF-1100E Andrew and Taxi

    https://codeforces.com/contest/1100/problem/E

    知识点:

    • 二分
    • 判断图中是否有环

    题意: 一个有向图,每边有一条边权,对于一个值x,可以使得边权小于等于x的边反转,求最小的x,使得某些边反转之后图中没有环

    分析:Suppose we have k traffic controllers. They can turn all edges whose weight is less than or equal to kk. Then let's remove all these edges from the graph, make a topological sorting of the remaining graph, and orient the other edges in the order of topological sorting. If there are cycles left in the graph after removing the edges, then we cannot get rid of them, having k traffic controllers. Otherwise, by adding edges we will not add new loops. The parameter k can be iterated through a binary search. Also in binary search, you can go through not all possible values of k, but only the values that are on the edges.

    Complexity — O((n+m)logC)or O((n+m)logm

    假如我们有k个交通管理员(即x),它们可以反转所有边权小于等于x的边,然后先把这些边从图中移除,拓扑排序这个图,如果这个图中还有环,那么我们应该使k变大。我们可以二分判定这个k,或者直接遍历所有边权即可。

    下面方面使用dfs获得每个结点被访问的时间戳(不是dfs序列),因为这个题我们可以通过检测每个边的两端点的时间戳是否和原来方向相反来判断是否需要翻转。而一般的我们确实需要用拓扑排序来看是否有边没有遍历从而得到是否有环存在。(由于拓扑排序必须以入读为0的点开始)

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,a[100005],b[100005],c[100005],pos[100005],cur;
    vector<int> v[100005],e;
    //获得每个结点的时间戳
    void dfs(int node)
    {
    	pos[node]=1;
    	for(int u:v[node])
            if(!pos[u])
                dfs(u);
    	pos[node]=cur--;;
    }
    bool check(int x)
    {
        //清空处理
    	for(int i=1;i<=n;i++) v[i].clear();
        for(int i=0;i<=n;i++)pos[i]=0;
    	e.clear();
        //移除翻转的边
    	for(int i=0;i<m;i++)
            if(c[i]>x)
                v[a[i]].push_back(b[i]);
    	cur=m;
    	for (int i=1;i<=n;i++)
            if(!pos[i])
            	dfs(i);
    	for(int i=0;i<m;i++)
    	{
            //判断是否有环
    		if(pos[a[i]]>pos[b[i]])
    		{
    			if(c[i]>x) return false;
    			e.push_back(i+1);
    		}
    	}
    	return true;
    }
    int main()
    {
        ios_base::sync_with_stdio(false);
    	cin>>n>>m;
    	for(int i=0;i<m;i++)
            cin>>a[i]>>b[i]>>c[i];
        //二分答案
    	int st=0,en=1e9;
    	while(st!=en)
    	{
    		int mid=(st+en)/2;
    		if(check(mid)) en=mid;
    		else st=mid+1;
    	}
    	check(st);
    	cout<<st<<" "<<e.size()<<endl;
    	for(int i:e) cout<<i<<" ";
    	return 0;
    }
    
  • 相关阅读:
    Javascript 如何识别数组
    新手 如何搭建一个vue项目详解
    javasScript 七种数据类型
    WPF实现动画的几种方式及其小案例
    问题清单
    2020软件工程个人作业06——软件工程实践总结作业
    我的“捡漏”生涯——小黄衫篇
    2020软件工程作业05
    2020软件工程作业03
    Python: list indices must be integers or slices, not float问题
  • 原文地址:https://www.cnblogs.com/1625--H/p/10279583.html
Copyright © 2011-2022 走看看