• 【SCC】Proving Equivalences UVALive


    传送门:https://vjudge.net/problem/UVALive-4287

    分析

    强连通分量(SCC) + 有向无环图(DAG) 的性质
    由 SCC 性质知,一个 CC 内的点可以相互到达(也就是里面的定理已经可以相互证明了),所以我们使用 SCC 将问题转化为给定一个 DAG,求使 DAG 变成一个 CC 的最小连边数

    下面我们专注于讨论下面的 Q
    Q:给定一个 DAG,求使 DAG 变成一个 CC(连通分量) 的最小连边数

    答案是多少呢?先给出结论:(max(cntS, cntT)) (出度为 (0) 的点数与入度为 (0) 的点数的最大值)。

    为什么呢?
    我们以 (cntT) 较大的情况为例,(cntS) 较大的情况可类似得到。

    (T) 较多时,每一个 (T) 点都必须要向着 (S) 点连边,具体方案构造新图(CC)的方案是先让每个 (S) 被不同的 (T) 连入,然后剩余的 (T) 随意连 (S) 。这样的构造方案一定能让新图中的任意两点相互到达:因为一个点 (u) 要到另一个点 (v),我们一定能让 (u) 先到一个 (T) 然后折返回一个通向 (v)(S)

    这样的方案显然是最优的,因为你至少要让所有 (T) 都向 (S) 连一条边。

    #pragma GCC optimize("O3")
    #include<bits/stdc++.h>
    using namespace std;
    #define endl '
    '
    #define debug(x) cerr << #x << ": " << x << endl
    #define pb(a) push_back(a)
    #define set0(a) memset(a,0,sizeof(a))
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define dwn(i,a,b) for(int i=(a);i>=(b);i--)
    #define ceil(a,b) (a+(b-1))/b
    #define INF 0x3f3f3f3f
    #define ll_INF 0x7f7f7f7f7f7f7f7f
    typedef long long ll;
    typedef pair<int,int> PII;
    typedef pair<double,double> PDD;
    
    inline void read(int &x) {
        int s=0;x=1;
        char ch=getchar();
        while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
        x*=s;
    }
    
    const int N=2e4+5, M=1e5+5;
    
    int n, m;
    
    struct node{
    	int to, next;	
    }e[M];
    
    int h[N], tot;
    
    void add(int u, int v){
    	e[tot].to=v, e[tot].next=h[u], h[u]=tot++;
    }
    
    int ts, dfn[N], low[N];
    int stk[N], top;
    int id[N], cnt;
    bool ins[N];
    void tarjan(int u){
    	dfn[u]=low[u]=++ts;
    	stk[++top]=u, ins[u]=true;
    	for(int i=h[u]; ~i; i=e[i].next){
    		int go=e[i].to;
    		if(!dfn[go]){
    			tarjan(go);
    			low[u]=min(low[u], low[go]);
    		}else if(ins[go]) low[u]=min(low[u], dfn[go]);
    	}
    	
    	if(dfn[u]==low[u]){
    		int y;
    		cnt++;
    		do{
    			y=stk[top--], ins[y]=false, id[y]=cnt; 
    		}while(y!=u);
    	}
    }
    
    int din[N], dout[N];
    
    int main(){
    	int T; read(T);
    	while(T--){
    		memset(h, -1, sizeof h);
    		set0(dfn); set0(low);
    		ts=tot=top=cnt=0;
    		
    		set0(din), set0(dout);
    		
    		cin>>n>>m;
    		while(m--){
    			int u, v; read(u), read(v);
    			add(u, v);
    		}
    		
    		rep(i,1,n) if(!dfn[i]) tarjan(i); // get the DAG
    
    		rep(i,1,n) for(int j=h[i]; ~j; j=e[j].next){
    			int go=e[j].to;
    			if(id[i]!=id[go]) dout[id[i]]++, din[id[go]]++;
    		}
    		
    		int cntS=0, cntT=0;
    		rep(i,1,cnt)
    			if(!din[i] && !dout[i]) cntS++, cntT++;
    			else if(!din[i]) cntS++;
    			else if(!dout[i]) cntT++;
    		
    		cout<<(cnt==1? 0: max(cntS, cntT))<<endl;
    	}
        return 0;
    }
    
  • 相关阅读:
    无需认证的mail,适用于ZABBIX等运维系统
    Linux交换分区使用过多的处理办法
    zookeeper的单实例和伪集群部署
    Zookeeper分布式集群原理与功能
    Nginx禁止IP直接访问网站
    镜像站地址汇总
    Nginx反向代理后端多节点下故障节点的排除思路
    Redis主从复制与高可用方案
    http_proxy_module模块常用参数
    Nginx实现负载均衡的几种方式
  • 原文地址:https://www.cnblogs.com/Tenshi/p/14974875.html
Copyright © 2020-2023  润新知