1. 程式人生 > >Equivalent Sets HDU - 3836 2011多校I tarjan強連通分量

Equivalent Sets HDU - 3836 2011多校I tarjan強連通分量

-- urn top define 內部 als ems CA head

題意:

  給一些集合 要求證明所有集合是相同的

  證明方法是,如果$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強連通分量