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;
    }
    
  • 相关阅读:
    PHPEXCEL使用实例
    php文件上传及mime类型大全
    此时无法停用连接。这个连接可能在用一个或多个不支持即插即用的协议,或者它是由其他用户或系统帐户初始化的。
    关于LineChart线条颜色和粗细的问题
    php读取excel类——PHPExcelReader
    windowsXP激活
    主机win7 虚拟机xp 不能上网的解决方案
    linux下载文件命令wget
    PHP 合并两个PDF成一个PDF文件利器 FPDI
    php 利用ExcelReader实现EXCEL转换成缓存
  • 原文地址:https://www.cnblogs.com/1625--H/p/10279583.html
Copyright © 2011-2022 走看看