UVALive 4287 Proving Equivalences(SCC、缩点+图的连通性)

来源:互联网 发布:miui分屏多任务软件 编辑:程序博客网 时间:2024/06/08 02:14

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2288

题目大意:有n个命题,先要证明他们全部等价,你的朋友已经做了m步等价关系的证明,让你算至少需要几部才能完成整个等价性的证明。

解题思路:比较基础的一道题吧。整个题目相当于给你m条单向边,问你最少补上几条边使得整个图强连通。很容易想到先缩点,整个图就是DAG了,然后对缩点后的SCC图,算出每个SCC团的入度和出度,那么要使整个图强连通,每个点的入度和出度都至少为1,所以答案就是max(入度为0的点个数,出度为0的点个数)。然后还有最重要的一点,也是这道题最恶心人的地方,那就是如果整个图先开始就是强连通的,那么答案就是0,不是1,要特判

代码如下:

#include<cstdio>#include<cstring>#include<vector>#include<stack>#include<algorithm>using namespace std;const int MAXN = 22222;vector <int> G[MAXN];int pre[MAXN],low[MAXN],sccno[MAXN];int dfs_clock,scc_cnt;stack <int> S;void dfs(int u){    pre[u] = low[u] = ++dfs_clock;    S.push(u);    for(int i = 0;i < G[u].size();i++)    {        int v = G[u][i];        if(!pre[v])        {            dfs(v);            low[u] = min(low[u],low[v]);        }        else if(!sccno[v])            low[u] = min(low[u],pre[v]);    }    if(low[u] == pre[u])    {        scc_cnt++;        for(;;)        {            int x = S.top();            S.pop();            sccno[x] = scc_cnt;            if(x == u) break;        }    }}void find_scc(int n){    memset(pre,0,sizeof(pre));    memset(sccno,0,sizeof(sccno));    dfs_clock = scc_cnt = 0;    for(int i = 0;i < n;i++)        if(!pre[i]) dfs(i);}int in[MAXN],out[MAXN];int main(){    int _;    scanf("%d",&_);    while(_--)    {        int n,m;        scanf("%d%d",&n,&m);        for(int i = 0;i < n;i++)            G[i].clear();        for(int i = 0;i < m;i++)        {            int a,b;            scanf("%d%d",&a,&b);            a--;            b--;            G[a].push_back(b);        }        find_scc(n);        memset(in,0,sizeof(in));        memset(out,0,sizeof(out));        for(int u = 0;u < n;u++)            for(int i = 0;i < G[u].size();i++)            {                int v = G[u][i];                if(sccno[u] != sccno[v])                {                    out[sccno[u]]++;                    in[sccno[v]]++;                }            }        int ans1 = 0,ans2 = 0;        for(int i = 1;i <= scc_cnt;i++)        {            if(in[i] == 0) ans1++;            if(out[i] == 0) ans2++;        }        int ans = max(ans1,ans2);        if(scc_cnt == 1) ans = 0;//特判,此题最阴险的地方!        printf("%d\n",ans);    }    return 0;}/*2 21 22 1*/


0 0
原创粉丝点击