Equivalent Sets HDU - 3836 2011多校I tarjan强连通分量

Posted 入侵检测引擎算法工程师/前ICPC选手

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Equivalent Sets HDU - 3836 2011多校I tarjan强连通分量相关的知识,希望对你有一定的参考价值。

题意:

  给一些集合 要求证明所有集合是相同的

  证明方法是,如果$A∈B$,$B∈A$那么$A=B$成立

  每一次证明可以得出一个$X∈Y$

  现在已经证明一些$A∈B$成立

  求,最少再证明多少次,就可以完成要求

分析

  其实就等价于给一个有向图,问你再加入多少个边可以使得图变为强连通图

  给一个图论经典结论:

  "对于一个有向无环图(DAG),若想让它成为强连通图,至少需要添加$max(a,b)$条边 $a$为入度为0的点的数量,$b$为出度为0的点的数量"

  而对于一个有向图,其每个强连通分量都互相可达,也就是只要到达任意一个点,即可到达内部所有的点

  现在,只要对于强连通分量进行缩点,再新图中统计出入度数即可得到答案

  *注意,如果强连通分量只有1个,答案应该是0而不是1

#include <bits/stdc++.h>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pp pair<int,int>
#define rep(ii,a,b) for(int ii=a;ii<=b;ii++)
#define per(ii,a,b) for(int ii=a;ii>=b;ii--)
#define show(x) cout<<#x<<"="<<x<<endl
#define show2(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl
#define show3(x,y,z) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl
#define showa(a,b) cout<<#a<<‘[‘<<#b<<"]="<<a[b]<<endl
using namespace std;
const int maxn=1e5+10;
const int maxm=1e6+10;
const int INF=0x3f3f3f3f;
int casn,n,m,k;
int stk[maxn],top,cnt,dfn[maxn],low[maxn],numc,belong[maxn],vis[maxn];
struct node {int to,cost,next;}e[maxm];int head[maxn],nume;
void add(int a,int b,int c=1){e[++nume]=(node){b,c,head[a]};head[a]=nume;}
void tdfs(int now){
	dfn[now]=low[now]=++cnt;
	stk[top++]=now;
	vis[now]=1;
	for(int i=head[now];i;i=e[i].next){
		int to=e[i].to;
		if(!dfn[to]){tdfs(to);low[now]=min(low[now],low[to]);}
		else if(vis[to]) low[now]=min(low[now],dfn[to]);
	}
	if(low[now]==dfn[now]){
		numc++;
		int to;
		do{
			to=stk[--top];
			belong[to]=numc;
			vis[to]=0;
		}while(to!=now);
	}
}
void tarjan(int numv=n){
	for(int i=1;i<=numv;i++){
		if(!dfn[i]) tdfs(i);
	}
}
void ginit(){
	nume=top=numc=cnt=0;
	memset(head,0,sizeof head);
	memset(dfn,0,sizeof dfn);
}
int din[maxn],dout[maxn];

int main(){
//#define test
#ifdef test
  freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endif

  while(cin>>n>>m){
    if(m==0) {
      cout<<n<<endl;
      continue;
    }
    ginit();
    memset(din,0,sizeof din);
    memset(dout,0,sizeof dout);
    for(int i=0;i<m;i++){
      int a,b;
      cin>>a>>b;
      add(a,b);
    }
    tarjan();
    for(int i=1;i<=n;i++){
      for(int j=head[i];j;j=e[j].next){
      	if(belong[i]==belong[e[j].to])continue;
        dout[belong[i]]++;
        din[belong[e[j].to]]++;
      }
    }
    int a=0,b=0;
    for(int i=1;i<=numc;i++){
      if(din[i]==0)a++;
      if(dout[i]==0)b++;
    }
    if(numc==1) a=b=0;
    cout<<max(a,b)<<endl;
  }

#ifdef test
  fclose(stdin);fclose(stdout);system("out.txt");
#endif
  return 0;
}

  

以上是关于Equivalent Sets HDU - 3836 2011多校I tarjan强连通分量的主要内容,如果未能解决你的问题,请参考以下文章

hdu 3836 Equivalent Sets trajan缩点

hdu 3836 Equivalent Sets(强连通分量--加边)

HDU 3836 Equivalent Sets(强连通分量)

hdu 3836 Equivalent Sets

HDU - 3836 Equivalent Sets (强连通分量+DAG)

Equivalent Sets HDU - 3836 (Tarjan)