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;
    }
    
  • 相关阅读:
    APP之百度地图SDK的AK值获取(android)
    横向滚动菜单-选中标题居中显示
    函数按引用传参问题
    js验证提交
    Java servlet ajax
    数据库3种读
    mybatis插件
    mybatis 缓存
    从前端对象中获取的文本变为字符串,并替换其中一些指定的字符
    多个窗口开启后,切换到指定title的窗口
  • 原文地址:https://www.cnblogs.com/1625--H/p/10279583.html
Copyright © 2011-2022 走看看