HDU 3836 Equivalent Sets【强连通分量】
题意: 知道了一些集合的包含关系,问至少还要知道多少个包含关系才能证明这些集合是相互等价的。
分析: 看出是强连通分量的模型就不难了。 最少加多少对关系使得每个集合等价,相当于在图中加入一些边,使得原图任意两个点互达即强连通,
找出这个边数即可。
#include<stdio.h> #include<string.h> #define maxn 20002 #define clr(x)memset(x,0,sizeof(x)) struct node { int to,next; }e[1000000]; int tot; int head[maxn]; void add(int s,int u) { e[tot].to=u; e[tot].next=head[s]; head[s]=tot++; } int top,ti,sn; int dfn[maxn]; int low[maxn]; int col[maxn]; int stack[maxn]; bool ins[maxn]; void tarjan(int u) { dfn[u]=low[u]=++ti; stack[++top]=u; ins[u]=true; int i,k; for(i=head[u];i;i=e[i].next) { k=e[i].to; if(dfn[k]==0) { tarjan(k); if(low[k]<low[u]) low[u]=low[k]; } else if(ins[k]&&dfn[k]<low[u]) low[u]=dfn[k]; } if(dfn[u]==low[u]) { sn++; do { k=stack[top--]; ins[k]=false; col[k]=sn; }while(k!=u); } } int id[maxn]; int od[maxn]; int main() { int n,m,i,j; while(scanf("%d%d",&n,&m)!=EOF) { int a,b; tot=1; ti=0; sn=0; top=0; clr(head); clr(low); clr(dfn); clr(col); clr(ins); while(m--) { scanf("%d%d",&a,&b); add(a,b); } for(i=1;i<=n;i++) if(dfn[i]==0) tarjan(i); if(sn==1) printf("0\n"); else { clr(id); clr(od); int in=0,out=0; for(i=1;i<=n;i++) for(j=head[i];j;j=e[j].next) { int k=e[j].to; if(col[i]!=col[k]) { id[col[k]]++; od[col[i]]++; } } for(i=1;i<=sn;i++) { if(id[i]==0) in++; if(od[i]==0) out++; } printf("%d\n",in>out?in:out); } } return 0; }