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(强连通分量)