HDU 3836 强联通

题意:如果A是B的子集,B是B的子集,那么A,B相等,,给出一系列的关系,求还需要多少关系才能证明所有的集合都相等;

分析:典型的强联通,,需要建多少边才能使得整个图联通;

解法:1,求出所有的缩点,,2,每个缩点的初度,入度是否为零,,3,不为零的出度之和与不为零的入度之和的最大值即为所求;

当然,提醒一下,自边,重边,虽然这题应该没影响

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
using namespace std ;

const int N = 20000 + 11 ;
const int M = 50000 + 11 ;

struct Graph {
    struct Edge {
        int e ;
        int next ;
    };

    Edge err[M] ;
    int dfn[N] , low[N] , instack[N] ;
    int head[N] ;
    bool degreein[N] ;
    bool degreeout[N] ;
    vector<int> stk ;
    vector<pair<int , int> > que ;
    int idx , color  , visit_time ;
    int n , m ;

    void add_edge(int& a , int& b) {
        err[idx].e = b;
        err[idx].next = head[a] ;
        head[a] = idx++ ;
    }

    void addinfo() {
        int a , b ;
        while(m--) {
            scanf("%d%d",&a,&b);
            if(a == b) continue ;
            add_edge(a , b) ;
        }
    }

    void init() {
        memset(head , -1 , sizeof(head)) ;
        memset(degreein , 0 , sizeof(degreein)) ;
        memset(degreeout , 0 , sizeof(degreeout)) ;
        memset(instack , 0 , sizeof(instack)) ;
        idx = 1 , color = 2 , visit_time = 0 ;
        que.clear() ;
        stk.clear() ;

    }

    void dfs(int site) {
        stk.push_back(site) ;
        instack[site] = 1 ;
        dfn[site] = low[site] = ++visit_time ;
        for(int i = head[site] ; i != -1 ; i = err[i].next) {
            int e = err[i].e ;
            if(!instack[e]) {
                dfs(e) ;
                 low[site] = min(low[site] , low[e]) ;
            }else if(instack[e] == 1){//开始这里写错了,没有if,,
                low[site] = min(low[site] , dfn[e]) ;
            }
            if(instack[e] > 1) {
                que.push_back(make_pair(site , instack[e])) ;
            }
        }
        if(low[site] == dfn[site]) {
            int tmp ;
            while(stk.back() != site) {
                tmp = stk.back() ;
                stk.pop_back() ;
                instack[tmp] = color ;
            }
            stk.pop_back() ;
            instack[site] = color++ ;
        }
    }



    void std_fun() {
        init() ;
        addinfo() ;
        for(int i = 1 ; i <= n ;++i) {
            if(instack[i] == 0) {
                dfs(i) ;
            }
        }
        while(!que.empty()) {
            pair<int ,int> tmp = que.back() ;
            que.pop_back() ;
            if(instack[tmp.first] != tmp.second) {
                degreeout[instack[tmp.first]] = true ;
                degreein[tmp.second] = true ;
            }
        }
        int a = 0 , b = 0 ;
        for(int i = 2 ; i < color ; ++i) {
            if(degreein[i] == false) ++a ;
            if(degreeout[i] == false) ++b ;
        }
        if(color == 3) {
            printf("0\n");
        }else {
            printf("%d\n" , max(a , b)) ;
        }
    }
}g ;

int main() {
    while(scanf("%d%d",&g.n ,&g.m)==2) {
        g.std_fun() ;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值