美文网首页
POJ 2186 Popular Cows 强连通分量分解

POJ 2186 Popular Cows 强连通分量分解

作者: 无令便逐风 | 来源:发表于2018-03-27 17:56 被阅读0次

题目链接戳这里
具体可以参考挑战程序设计竞赛二4.3节

强连通分量分解

对于一个有向图顶点的子集S,如果在S内任取2个顶点u和v,都有一条u到v的路径,则S是强连通的.任何有向图都可以分解成若干不相交的强连通分量.
强连通分量分解的思路是:

  • 先从某个源点进行一次dfs,作用是给顶点打标记,而且是按后序遍历来标记.
  • 得到的标记中,标号在最后打上的就是搜索树的根.此时把边都反向,再进行一次dfs
  • 边反向之后,强连通分量内部的点的可达性不受影响,而内部点前往该强连通分量之外的道路因为反向被切断,从而达到分解的效果

这里有道例题,有向边a->b意味着a牛认为b牛是红人,且这种关系有传递性,即a->b, b->c, 则a->c成立,这可以理解成有向图的可达性,求被其它所有牛认为是红人的牛的总数.

分析

对于那些被所有人认为是红人的牛中,互相定然也认为对方是红人,就会形成一个强连通分量.一个有向图可能不止一个强连通分量,唯一可能成为解的集合必然是拓扑序最后的强连通分量,如图所示:


只有被所有牛崇拜才能当选

所以,问题转换成,判断最后的这个强连通分量是否与其它所有顶点都可达即可.又因为强连通分量内部肯定所有牛之间都可达,所以在最后这个强连通分量随便抓一只牛u逆向dfs,看是否能遍历完所有牛即可.

// #include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

#define mst(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<(b);++i)
#define pb push_back
const int inf = 0x3f3f3f3f, maxN = 10005;
int N, M;
// G是原图 rG是逆边之后的图
// vs存储后序遍历节点路径
// topo是每个点所在的强连通分量号 scc返回强连通分量个数
// dfs目的是得vs,rdfs目的是统计强连通个数及给顶点标号
vector<int> G[maxN], rG[maxN], vs;
int used[maxN], topo[maxN];

void add_edge(int from, int to) {
    G[from].pb(to);
    rG[to].pb(from);
}
void dfs(int v) {
    used[v] = 1;
    rep(i, 0, G[v].size())
        if (!used[G[v][i]])
            dfs(G[v][i]);
    vs.pb(v);
}
void rdfs(int v, int k) {
    used[v] = 1;
    topo[v] = k;
    rep(i, 0, rG[v].size())
        if (!used[rG[v][i]])
            rdfs(rG[v][i], k);
}
int scc() {
    mst(used, 0);
    vs.clear();
    rep(v, 0, N)
        if (!used[v])
            dfs(v);
    mst(used, 0);
    int k = 0;
    for (int i = vs.size() - 1; i >= 0; --i)
        if (!used[vs[i]])
            rdfs(vs[i], k++);
    return k;
}
void solve() {
    int n = scc();
    int u = 0, num = 0;
    rep(v, 0, N) {
        if (topo[v] == n - 1) {
            u = v;
            ++num;
        }
    }
    mst(used, 0);
    rdfs(u, 0);
    rep(v, 0, N) {
        if (!used[v]) {
            num = 0;
            break;
        }
    }
    printf("%d", num);
}
int main() {
    // freopen("data.in", "r", stdin);
    scanf("%d %d", &N, &M);
    int from, to;
    rep(i, 0, M) {
        scanf("%d %d", &from, &to);
        add_edge(from - 1, to - 1);
    }
    solve();
    return 0;
}

相关文章

  • POJ 2186 Popular Cows 强连通分量分解

    题目链接戳这里具体可以参考挑战程序设计竞赛二4.3节 强连通分量分解 对于一个有向图顶点的子集S,如果在S内任取2...

  • tarjan

    tarjan寻找出度为0的强连通分量,从小到大输出此强连通分量中的点 poj 2553 The Bottom of...

  • 图论(二)

    强连通分量 POJ 3180: The Cow Prom找出有多少个点数大于等于2的scc即可。代码如下 POJ ...

  • tarjan

    tarjan:寻找出度为0的强连通分量,并求出该强连通分量中有多少个点。 sig表示的是强连通分量的个数其中col...

  • 强连通分量

    强连通分量 相关概念 强连通:在有向图G中,如果两个顶点u,v间存在一条u到v的路径且也存在 一条v到u的路径,则...

  • tarjan-寻找图中有多少个强连通分量

    tarjan寻找图中有多少个强连通分量 hdu 1269 迷宫城堡判断图否是属于一个强连通分量

  • 强连通分量和Kosaraju算法

    内容概要: 基于深度优先后序遍历的DAG图拓扑排序 强连通分量 求解强连通分量Kosaraju算法 拓扑排序的另一...

  • 数据结构与算法--图论之寻找连通分量、强连通分量

    数据结构与算法--图论之寻找连通分量、强连通分量 寻找无向图的连通分量 使用深度优先搜索可以很简单地找出一幅图的所...

  • Kosaraju算法详解

    Kosaraju算法是干什么的? Kosaraju算法可以计算出一个有向图的强连通分量 什么是强连通分量? 在一个...

  • 强连通分量算法

    计算机系DSA第二次Programming Assignment中第三题涉及到这个算法 【问题描述】 一个有向图中...

网友评论

      本文标题:POJ 2186 Popular Cows 强连通分量分解

      本文链接:https://www.haomeiwen.com/subject/hnuscftx.html