您的位置:首页 > 产品设计 > UI/UE

LA-4287 & HDOJ-2767 Proving Equivalences 解题报告

2014-11-24 20:46 435 查看
强连通分量题。题意:在数学中经常需要完成若干个命题的等价证明。比如有4个命题a,b,c,d,我们从a证明到b,从b证明到a,然后b到c,c到b,最后c到d,d到c。这样就证明了4个命题等价,当然也可以这样证明,从a到b,b到c,c到d,d到a。任务是要求证明n个命题全部等价,现在已经完成了m次证明,问最少还需要几次证明就可以完成整个证明?

我的解题思路:将每一个命题看做一个节点,那么n个命题等价则说明这n个节点所构成的图强连通。要使原图强连通,先算一下原图中强连通分量的个数。再判断一下出度为0的强连通分量个数x和入度为0的强连通分量个数y,那么最少需要max(x, y)次证明才能使原图强连通。注意:假如原图已经强连通(原图强连通分量个数为1),那么就说明这n个命题已经是等价的了。

我的解题代码:强连通分量Tarjan算法+缩点

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

#define N 30003

vector <int> e
;
int dfn
, low
;
int stack
, stop;
int vis
;
int belong
;
int timer;
int sccn;
int indeg
;
int outdeg
;
int n, m;

void InitRead();

void DataProcess();

void Tarjan(int x);

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        InitRead();
        DataProcess();
    }
    return 0;
}

void InitRead()
{
    scanf("%d %d", &n, &m);
    memset(vis, 0, sizeof(vis));
    memset(indeg, 0, sizeof(indeg));
    memset(outdeg, 0, sizeof(outdeg));
    stop = timer = sccn = 0;
    for (int i=1; i<=n; ++i) e[i].clear();
    int a, b;
    for (int i=0; i<m; ++i)
    {
        scanf("%d %d", &a, &b);
        e[a].push_back(b);
    }
    return;
}

void DataProcess()
{
    for (int i=1; i<=n; ++i)
    {
        if (!vis[i])
        {
            Tarjan(i);
        }
    }
    if (sccn == 1)      //特判,假如原图已经强连通,那么不需要继续证明了
    {
        puts("0");
        return;
    }
    for (int i=1; i<=n; ++i)
    {
        int size = e[i].size();
        for (int j=0; j<size; ++j)
        {
            if (belong[i] != belong[e[i][j]])
            {
                outdeg[belong[i]]++;
                indeg[belong[e[i][j]]]++;
            }
        }
    }
    int ansin = 0, ansout = 0;
    for (int i=1; i<=sccn; ++i)
    {
        if (outdeg[i] == 0) ansout++;
        if (indeg[i] == 0) ansin++;
    }
    printf("%d\n", max(ansin, ansout));
    return;
}

void Tarjan(int x)
{
    int y;
    dfn[x] = low[x] = ++timer;
    stack[stop++] = x;
    vis[x] = 2;
    int size = e[x].size();
    for (int i=0; i<size; ++i)
    {
        y = e[x][i];
        if (!vis[y])
        {
            Tarjan(y);
            low[x] = min(low[x], low[y]);
        }
        else if (vis[y] == 2)
        {
            low[x] = min(low[x], dfn[y]);
        }
    }
    if (dfn[x] == low[x])
    {
        sccn++;
        do
        {
            y = stack[--stop];
            vis[y] = 1;
            belong[y] = sccn;
        } while (x != y);
    }
    return;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: