Strongly connected component

本文介绍了一种利用Tarjan算法求解有向图中强连通分量的方法,并通过一个具体问题实例展示了如何计算互殴后至少能留下的怪兽数量。该问题通过构造有向图并寻找强连通分量来解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述
这里写图片描述

思路:这道题目是让我们求出在经过旷日持久的互殴后至少能够留下多少只怪兽。本质是要我们根据怪兽间关系,构造有向图寻找强连通分量。如果有两个强连通分量那么每个强连通分量中至少会有一只怪兽留下,假设一个有向图中强连通分量个数为n,如果强连通分量间互不连通,那么至少能够留下n只怪兽;若两个强连通分量之间存在一条边相连,那个怪兽的数量为n-1。这道题使用Tarjan来寻找强连通分量,代码实现如下:

class Solution {
private:
    stack<int> s;
    vector<int> sccno;//标示每个点所属连通分量
    vector<vector<int> > graph;
    vector<int> pre, lowlink;
    vector<bool> visit;
    int scc_cnt;
    int cnt;


    void Tarjan(int v) {
        pre[v] = lowlink[v] = ++cnt;
        s.push(v);

        for (int j = 0; j < graph[v].size(); j++) {
            int u = graph[v][j];

            if (!pre[u]) {
                Tarjan(u);
                lowlink[v] = min(lowlink[v], lowlink[u]);
            } else if (!sccno[u]) {
                lowlink[v] = min(lowlink[v], pre[u]);
            }
        }

        if (pre[v] == lowlink[v]) {
            scc_cnt++;
            do {
                int idx = s.top(); s.pop();

                sccno[idx] = scc_cnt;
            } while (idx != v);
        }
    }

    void find_scc(int n) {
        //init
        sccno.resize(n, 0);
        pre.resize(n, 0);
        lowlink.resize(n, 0);
        scc_cnt = 0;
        cnt = 0;

        for (int i = 0; i < n; i++) {
            if (!pre[i]) Tarjan(i);
        } 
    }
public:
    int minLeftMonsters(vector<vector<char> > G) {
        int n = G.size();

        graph.resize(n);
        for (int i = 0; i < n; i++) {
            for (int j = i+1; j < n; j++) {
                if (G[i][j] == '+') graph[j].push_back(i);
                else if (G[i][j] == '-') graph[i].push_back(j);
            }
        }
        find_scc(n);

        int res = scc_cnt;

        visit.resize(res+1, false);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < graph[i].size(); j++) {
                int x = sccno[graph[i][j]];

                if (x == sccno[i]) continue;
                if (!visit[x]) {//连通分量之间存在相连边
                    res--;
                    visit[x] = true;
                }
            }
        }
        sccno.clear();
        pre.clear();
        lowlink.clear();
        visit.clear();
        for (int i = 0; i < n; i++) graph[i].clear();
        while (!s.empty()) s.pop();

        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值