zoukankan      html  css  js  c++  java
  • HDU2767

    /*
    *题目大意:
    *        在数学里面有两种关系,一种是充分条件,即对于集合p,q,p => q,
    *        另一种是等价关系,p => q && q =>p, 这两种关系都具有传递性,p
    *        => q 可以对应到有节点p到节点q有一条边。问:给定一些集合的充分
    *        性关系,确定出若让所有集合都等价,还需在添加最少的充分性条件。
    *解题思路:
    *        有向图加最少边变强连通,模板题
    */
    View Code
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    const int MAXN = 20005;
    
    typedef struct _node
    {
        int v, next;
    }N;
    N edge[MAXN * 3];
    int dfn[MAXN], low[MAXN], step;
    int inS[MAXN], id[MAXN], scc, myS[MAXN], top;
    int in[MAXN], out[MAXN], cntEdge, head[MAXN];
    
    void init()
    {
        cntEdge = step = scc = top = 0;
        for(int i = 0; i < MAXN; i++)
        {
            head[i] = -1;
            dfn[i] = low[i] = -1;
            id[i] = -1;
            in[i] = out[i] = 0;
            inS[i] = 0;
        }
    }
    
    void tarjan(int n)
    {
        dfn[n] = low[n] = ++step;
        myS[top++] = n;
        inS[n] = 1;
        for(int f = head[n]; f != -1; f = edge[f].next)
        {
            int son = edge[f].v;
            if(dfn[son] == -1)
            {
                tarjan(son);
                low[n] = min(low[n], low[son]);
            }
            else if(inS[son] != 0)
                low[n] = min(low[n], dfn[son]);
        }
    
        if(low[n] == dfn[n])
        {
            int tmp;
            do
            {
                tmp = myS[--top];
                inS[tmp] = 0;
                id[tmp] = scc;
            }while(myS[top] != n);
            scc++;
        }
    }
    
    void addEdge(int u, int v)
    {
        edge[cntEdge].v = v;
        edge[cntEdge].next = head[u];
        head[u] = cntEdge++;
    }
    
    
    
    int main(void)
    {
    #ifndef ONLINE_JUDGE 
        freopen("inHDU2767.txt", "r", stdin);
    #endif
    
        int n, m, cas;
        scanf("%d", &cas);
        while(cas--)
        {
            scanf("%d %d", &n, &m);
            init();
            int u, v;
            for(int i = 0; i < m; i++)
            {
                scanf("%d %d", &u, &v);
                addEdge(u, v);
            }
    
            for(int i = 1; i <= n; i++)
            {
                if(dfn[i] == -1)
                    tarjan(i);
            }
            for(int i = 1; i <= n; i++)
            {
                for(int j = head[i]; j != -1; j = edge[j].next)
                {
                    u = i, v = edge[j].v;
                    if(id[u] == id[v])
                        continue;
                    else
                    {
                        in[id[v]]++;
                        out[id[u]]++;
                    }
                }    
            }
            int inNum = 0, outNum = 0;
            for(int i = 0; i < scc; i++)
            {
                if(!in[i])
                    inNum++;
                if(!out[i])
                    outNum++;
            }
            if(scc >= 2)
                printf("%d\n", max(inNum, outNum));
            else
                printf("0\n");
        }
        return 0;
    }
  • 相关阅读:
    202006leetcode刷题记录
    二分查找详解
    并查集
    202005leetcode刷题记录
    基于地震数据的Spark数据处理与分析
    Java日志框架:logback详解
    java 多线程
    Oracle表恢复(truncate)
    关于软件开发,你老板不知道的7件事
    调用oracle 分页存储过程 返回游标数据集
  • 原文地址:https://www.cnblogs.com/cchun/p/2645071.html
Copyright © 2011-2022 走看看