UVALIVE 4287 Proving Equivalences Tarjan求强连通分量

来源:互联网 发布:淘宝全屏海报轮播代码 编辑:程序博客网 时间:2024/06/05 16:26

题目链接:https://vjudge.net/problem/UVALive-4287

题意:有n个命题,已知其中的m个推导,要证明n个命题全部等价(等价具有传递性),最少还需要做出几次

推导

解法:由已知的推导可以建一张无向图,则问题变成了最少需要增加几条边能使图变成强连通图。找出所有的

强连通分量,将每一个连通分量视作一个大节点,则整张图变成了一张DAG。设出度为0的大节点个数为a,

入度为0的大节点个数为b,则答案就是max(a,b)。为什么是这样呢?因为要使等价证明前进下去,每个大节

点的出度和入度都必须不能是0,注意特判整个图是强连通分量的情况

///UVALIVE 4287#include <bits/stdc++.h>using namespace std;const int maxn = 20005;int n, m, low[maxn], dfn[maxn], dfs_clk, scc, top;int in[maxn], out[maxn], s[maxn], belong[maxn], head[maxn], edgecnt;bool inq[maxn];struct edge{    int v, nxt;    edge(){}}E[maxn*4];void init(){    memset(head, -1, sizeof(head));    edgecnt=0;}void add(int u, int v){    E[edgecnt].v = v, E[edgecnt].nxt = head[u], head[u] = edgecnt++;}void tarjan(int x){    int now=0;    dfn[x]=low[x]=++dfs_clk;    s[++top]=x; inq[x]=1;    for(int i=head[x]; i+1; i=E[i].nxt){        int to=E[i].v;        if(!dfn[to]){            tarjan(to);            low[x]=min(low[x],low[to]);        }        else if(inq[to]){            low[x]=min(low[x],dfn[to]);        }    }    if(low[x]==dfn[x]){        ++scc;        while(now!=x){            now=s[top];top--;            belong[now]=scc;            inq[now]=0;        }    }}int main(){    int T; scanf("%d", &T);    while(T--){        scanf("%d%d", &n,&m);        init();        while(m--){            int u, v;            scanf("%d%d", &u,&v);            add(u, v);        }        memset(inq, 0, sizeof(inq));        memset(low, 0, sizeof(low));        memset(dfn, 0, sizeof(dfn));        memset(belong, 0, sizeof(belong));        memset(in, 0, sizeof(in));        memset(out, 0, sizeof(out));        memset(s, 0, sizeof(s));        dfs_clk = scc = top = 0;        for(int i=1; i<=n; i++){            if(!dfn[i]){                tarjan(i);            }        }        for(int i=1; i<=scc; i++){            in[i] = out[i] = 0;        }        int a = 0, b = 0;        for(int i=1; i<=n; i++){            for(int j=head[i]; j+1; j=E[j].nxt){                int v = E[j].v;                if(belong[i]!=belong[v]){                    out[belong[i]]=in[belong[v]]=1;                }            }        }        for(int i=1; i<=scc; i++){            if(!in[i]) a++;            if(!out[i]) b++;        }        int ans = max(a, b);        if(scc==1){            ans=0;        }        printf("%d\n", ans);    }    return 0;}
0 0
原创粉丝点击