UVALive - 4287 Proving Equivalences

给定n个命题之间的已经证明的关系如 a b表示已经证明蕴含式a→b,要求还需要再作多少次证明使得所有的命题都是等价的.将每个命题看成一个点,已经证明的命题之间连一条边,问题转化为添加多少条单向边使得图成为一个强连通分量.

先求出所有的强连通分量,然后缩点构成一个SCC图,统计其中入度为0的点个数a,以及出度为0的点的个数b,max(a,b)就是需要再作的证明.注意当图一开始就是强连通时,不需要作出证明了.

来自刘汝佳算法训练指南代码:

#include <iostream>
#include <sstream>
#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <string>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#define esp 1e-6
#define pi acos(-1.0)
#define pb push_back
#define mp(a, b) make_pair((a), (b))
#define in  freopen("in.txt", "r", stdin);
#define out freopen("out.txt", "w", stdout);
#define print(a) printf("%d\n",(a));
#define bug puts("********))))))");
#define stop  system("pause");
#define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++)
#define pragma comment(linker, "/STACK:102400000, 102400000")
#define inf 0x0f0f0f0f

using namespace std;
typedef long long  LL;
typedef vector<int> VI;
typedef pair<int, int> pii;
typedef vector<pii,int> VII;
typedef vector<int>:: iterator IT;
const int maxn = 22222;
int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;
int in0[maxn], out0[maxn];
VI g[maxn];
stack<int> S;
void dfs(int u)
{
    S.push(u);
    lowlink[u] = pre[u] = ++dfs_clock;
    for(int i = 0; i < g[u].size(); i++)
    {
        int v = g[u][i];
        if(!pre[v])
        {
            dfs(v);
            lowlink[u] = min(lowlink[u], lowlink[v]);
        }
        else if(!sccno[v])
        {
            lowlink[u] = min(lowlink[u], pre[v]);
        }
    }
    if(lowlink[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 main(void)
{in
    int n, m;
    int T;
    for(int t = scanf("%d", &T); t <= T; t++)
    {
        for(int i = 0; i < maxn; i++)
            g[i].clear();
        memset(in0, 1, sizeof(in0));
        memset(out0, 1, sizeof(out0));
        scanf("%d%d", &n, &m);
        while(m--)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            u--, v--;
            g[u].pb(v);
        }
        find_scc(n);
        for(int u = 0; u < n; u++)
            for(int i = 0; i < g[u].size(); i++)
            {
                int v = g[u][i];
                if(sccno[v] != sccno[u])
                    in0[sccno[v]] = out0[sccno[u]] = 0;
            }
        int a = 0, b= 0;
        for(int i = 1; i <= scc_cnt; i++)
        {
            if(in0[i]) a++;
            if(out0[i]) b++;
        }
        int ans = 0;
        if(scc_cnt != 1) ans = max(a, b);
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(live)