HDU 4635 Strong connected | tarjan算法

#include<cstdio>
#include<cstring>
#include<iostream>
#include<iomanip>
#include<queue>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int int_max = 0x07777777;
const int int_min = 0x80000000;
int smaller (int a, int b) { return (a > b ? b : a); }
long long bigger (long long a, long long b) { return (a > b ? a : b); }
const int maxn = 200005;

vector<int> g[maxn];
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
int outs[maxn],ins[maxn],geshu[maxn];
stack<int> S;
void dfs (int u){
    pre[u] = lowlink[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);
            lowlink[u] = smaller(lowlink[u], lowlink[v]);
        }else if(!sccno[v]){
            lowlink[u] = smaller(lowlink[u], pre[v]);
        }
    }
    if(lowlink[u]==pre[u]){
        scc_cnt++;
        while (true) {
            int x = S.top();
            S.pop();
            sccno[x] = scc_cnt;
            if(x==u) break;
        }
    }
}
void find_scc (int n){
    dfs_clock = scc_cnt = 0;
    memset(sccno, 0, sizeof(sccno));
    memset(pre, 0, sizeof(pre));
    for(int i = 1; i <= n; i++){
        if(!pre[i]) dfs(i);
    }
}
long long N,M;
int main(int argc, const char * argv[])
{
    int T;
    scanf("%d", &T);
    int casecount = 1;
    while(T--){
        scanf("%d %d", &N, &M);
        for(int i = 0; i < maxn; i++) g[i].clear();
        for(int i = 0; i < M; i++){
            int x,y;
            scanf("%d %d", &x, &y);
            g[x].push_back(y);
        }
        find_scc(N);
        if(scc_cnt==1) printf("Case %d: -1\n",casecount++);
        else{
            memset(outs, 0, sizeof(outs));
            memset(ins, 0, sizeof(ins));
            memset(geshu, 0, sizeof(geshu));
            for(int i = 1; i <= N; i++){
                for(int j = 0; j < g[i].size(); j++){
                    if(sccno[i]!=sccno[g[i][j]]){
                        outs[sccno[i]]++;
                        ins[sccno[g[i][j]]]++;
                    }
                }
                geshu[sccno[i]]++;
            }
            long long result = 0;
            for(int i = 1; i <= scc_cnt; i++){
                if(outs[i]==0 || ins[i]==0){
                    result = bigger(result, N*(N-1)-M-(N-geshu[i])*geshu[i]);
                }
            }
            printf("Case %d: %lld\n",casecount++,result);
        }
    }
}
对一个有向图,找出所有的强连通分量之后,把每一个强连通分量看成一个点,这些点当中肯定存在一个入度或者出度为零的点(用反证法证明)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值