• 【二分】【拓扑排序】CF1100E Andrew and Taxi


    【二分】【拓扑排序】CF1100E Andrew and Taxi

    题目链接

    题目大意

    给定一个有向图,改变其中某些边的方向,它将成为一个有向无环图。

    现在求一个改变边方向的方案,使得所选边边权的最大值最小。

    题目思路

    题目只要求所选择的所有的边的最大边权的边的边权最小,而并没有再继续要求修改的边数最少,也就是说只要满足前者,同时构造出一个可行解就行。

    • 二分:

      若最大的边权等于x,则获得对所有小于等于x的边的修改的权利。进而,若答案为x+1,也拥有同样甚至更大的修改权利,所以也是可行的。

    • 拓扑排序:

      两个作用:

      1. 是否存在环

        如果是环上的任意一点,则它始终无法加入到拓扑的队列中,于是加入过拓扑的队列的总点数小于总点数,则说明有环的存在。

        若假设不进行修改的边存在环,则说明当前二分的答案是错误的。

      2. 拓扑序

        要进行修改的边,可以认为是在一张图上先确定一定不修改的边后处在方向状态待定的边。

        而当由拓扑序低的点指向拓扑序高的点,即可保证新构建的图不存在环。若与原来的指向产生冲突则需要进行修改,否则保留原本指向即可。

    code

    #include <bits/stdc++.h>
    #define ll long long
    #define ull unsigned long long
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define MAX 1000005
    #define MOD 1000000007
    using namespace std;
    const int N = 3E5+5,M = 6E5+10;
    int n,m;
    
    struct edge{
    	int u,v,w,id,nxt;
    }es[M];
    
    int h[N],idx;
    void add(int u,int v,int w,int id)
    {
    	es[idx] = {u,v,w,id,h[u]};
    	h[u] = idx++;
    }
    
    int sta[N],du[N]; 
    vector<int > modis;
    bool check(int x)
    {
        for(int i=1;i<=n;i++) sta[i] = du[i] = 0;
    	 
    	for(int i=0;i<idx;i++) 
    	    if(es[i].w>x)//不动大的边, 将其保留下来 
    			du[ es[i].v ]++;
    	
    	queue<int > q;
    	for(int i=1;i<=n;i++)
    	    if(!du[i]) q.push(i);
    	    
    	int cnt = 0;
    	while(q.size())
    	{
    		int t = q.front();q.pop(); 
    		sta[t] = ++cnt;
    		for(int i = h[t];~i;i=es[i].nxt)
    		{
    			int v = es[i].v;
    			if(es[i].w<=x) continue; //跳过暂时忽略掉的边 
    			du[v]--;
    			if(!du[v]) q.push(v);
    		}
    	}
        
        if(cnt!=n) return false;
        //这里开始的modis都是满足条件的 
        modis.clear();
    	for(int i=0;i<idx;i++)
    	{
    		int u = es[i].u , v = es[i].v , w = es[i].w;
    		if(w>x) continue;
    		if(sta[u]>sta[v]) modis.push_back(es[i].id);
    	}
    	sort(modis.begin(),modis.end());
    	return true;
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        memset(h,-1,sizeof(h)); 
        cin>>n>>m;
        int maxn = 0;
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            cin>>u>>v>>w; 
            maxn = max(maxn,w);
            add(u,v,w,i);
        }
    	
        int l = 0, r = maxn , ans;
        while(l<=r)
        {
    	int mid = l + r >> 1;
    	if(check(mid))
    	{
    		r = mid - 1;
    		ans = mid;
    	}
    	else l = mid + 1;
        }
    	
        cout<<ans<<" "<<modis.size()<<endl;
        for(int i=0;i<modis.size();i++)
    	 cout<<modis[i]<<" ";
        return 0;
    }
    
    

  • 相关阅读:
    MAC OS系统替换homebrew使用阿里云的镜像源
    Javascript 交换两个变量的值
    Vue 中的 ref $refs
    Bluetooth M590 mouse problem Ubuntu
    Ubuntu 蓝牙鼠标的问题
    视频分享
    Vue项目中的文件/文件夹命名规范
    js打印div指定区域内容
    IntelliJ IDEA 配置
    idea安装
  • 原文地址:https://www.cnblogs.com/BeautifulWater/p/15920669.html
Copyright © 2020-2023  润新知