HDU 2767 Proving Equivalences && HDU 3836 Equivalent Sets 强连通

来源:互联网 发布:张强医生集团 知乎 编辑:程序博客网 时间:2024/05/22 00:21

两道题除了加了个case数之外其余的都一样 HDU 3836 最近学习了一下Tarjan算法,虽然一些具体的细节还不是太懂,这道题就是给定一些集合之间的关系,判断需要加多少边才能成为强连通图。求出连通分量以后缩点,遍历所有边,如果边的端点属于两个联通分量,就把起点所在的连通分量出度++,终点的入度++,最后遍历所有连通块,统计所有分量的出度和入度,取较大的值即可。注意当连通分量数目为1时答案为0.

#include <map>#include <cmath>#include <cstdio>#include <vector>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn = 20024;const int maxm = 50002;int n,m,ans,Index,scc,top,tot,sum;int low[maxn],dfn[maxn],Stack[maxn],num[maxn],head[maxn],Belong[maxn],in[maxn],out[maxn];bool Instack[maxn];struct Edge {    int from,to,next;    Edge():from(0),to(0),next(0) {}} edge[maxm];void addedge(int u,int v) {    edge[tot].from=u;    edge[tot].to=v,edge[tot].next=head[u];    head[u]=tot++;}void Tarjan(int u) {    int v;    low[u]=dfn[u]=++Index;    Stack[top++]=u;    Instack[u]=true;    for(int i=head[u]; i!=-1; i=edge[i].next) {        v=edge[i].to;        if(!dfn[v]) {            Tarjan(v);            low[u]=min(low[u],low[v]);        } else if(Instack[v])            low[u]=min(low[u],dfn[v]);    }    if(low[u]==dfn[u]) {        scc++;        do{            v=Stack[--top];            Instack[v]=false;            Belong[v]=scc;            num[scc]++;        }while(v!=u);    }}void solve() {    memset(dfn,0,sizeof(dfn));    memset(Instack,false,sizeof(Instack));    memset(num,0,sizeof(num));    memset(low,0,sizeof(low));    memset(Belong,0,sizeof(Belong));    memset(in,0,sizeof(in));    ans=Index=top=scc=0;    for(int i=1; i<=n; i++)        if(!dfn[i])            Tarjan(i);}int main() {    int x,y;    while(~scanf("%d%d",&n,&m)) {        memset(head,-1,sizeof(head));        tot=0;        for(int i=0; i<m; i++) {            scanf("%d%d",&x,&y);            addedge(x,y);        }        solve();        memset(in, 0, sizeof(in));        memset(out,0,sizeof(out));        for(int i=0; i<tot; i++) {            int u=Belong[edge[i].from];            int v=Belong[edge[i].to];            if(u!=v) in[v]++,out[u]++;        }        ans=sum=0;        for(int i=1;i<=scc;++i) {            if(in[i]==0) ans++;            if(out[i]==0) sum++;        }        if(scc==1) printf("0\n");        else printf("%d\n", max(ans,sum));    }    return 0;}


0 0