题目:https://www.acwing.com/problem/content/1176/
tarjan:O(n+m),,,这个tarjan算法,除了求强连通分量(合并完的环),还可以顺便求图中所有的环的数量(不是合并完的环),自己测的,没有证明,代码中的sss就是。

题意:如果A–》B,B–》C,那么A–》C,问在这个有向图中有多少个这样的A,除了A个点外的所有点都能有路走到A。

题解:暴力做法,就是枚举每一个点,看一下其他所有点是否都能到这个点,这个时间复杂度是n方级别的,肯定不行。
如果这个图有拓扑序列的话,那么按照这个拓扑序列走一遍,看看有一个出度为0的点,如果有一个出度为0的点,那么其它所有点就一定能走到这个点,但是这个图可能有环,所以它不一定有拓扑序列。
但是又可以发现,在这个题中,一个环中所有点是任意到达的,所以如果其它所有点都能到这个环,那么这个环中的所有点都是题目中要求的点,而且在这个环中,如果其中一个点可以走到环外的一个点,那么环中其它所有点也可以走到那个点,所以就可以把一个环看成一个点,把所有的环都压缩成一个点,那么就可以这个图就有拓扑序列了(当然,可能有环套环(最外层有个大环,里面的一些点又有一些小环)、环连环(俩个环通过都包括一个点)的情况,会把这些环一起都压缩成一个点),这样就可以做这个题了,而求一个图中的环的数量(这里的环的意义是环连环、环套环算是一个环,其实就是强连通分量),即求强连通分量的数量,用tarjan做法。

#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
//#include <unordered_map>
//#include <unordered_set>
//#include <bits/stdc++.h>
//#define int long long
#define pb push_back
#define pii pair<int, int>
#define mpr make_pair
#define ms(a, b) memset((a), (b), sizeof(a))
#define x first
#define y second
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
using namespace std;
inline int read() {char ch = getchar();int s = 0, w = 1;while (ch < '0' || ch > '9') {if (ch == '-') w = -1;ch = getchar();}while (ch >= '0' && ch <= '9') {s = s * 10 + ch - '0', ch = getchar();}return s * w;
}
const int N = 10010, M = 50010;
//int sss=0;
int n, m;
int h[N], e[M], ne[M], idx;//存图
int dfn[N], low[N], timestamp;//low记录这个点可以走到的最早时间点,dfn记录这个点的时间点,timestamp是时间戳
int stk[N], top;  //栈
bool in_stk[N]; //判断是否在栈里面
int id[N], scc_cnt, id_size[N];  //id是这个数在第几个连通块,scc_cnt是总共有几个连通块,id_size是这个这个连通块的数量
int dout[N];   //记录出度,,上面的尾tarjan板子需要用的,这个数组是处理这个题的
void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
void tarjan(int u) {dfn[u] = low[u] = ++timestamp;//记录本点的时间戳stk[++top] = u, in_stk[u] = true;//加入栈for (int i = h[u]; i != -1; i = ne[i]) { //找它连的所有边int j = e[i];if (!dfn[j]) {    //判断它是否走过,如果没走过就往下走tarjan(j);low[u] = min(low[u], low[j]); //找它能走的最早的点} else if (in_stk[j])   //如果它在栈里面,就说明这个点可以走到我这个点,我这个点也可以走到它,所以取最小low[u] = min(low[u], low[j]);//在这个上面这个分号前面加一个sss++}if (dfn[u] == low[u]) {//如果本点的时间点就是它能走到的最早的时间点,证明它要么是没有环,要么是环中最早出现的那个点int y;++scc_cnt;//更新增加连通块,找这之间所有的点,这些都是在这个连通块中do {y = stk[top--];in_stk[y] = false;id[y] = scc_cnt;//更新这个点指向的连通块id_size[scc_cnt]++;//给这个连通块增加规模} while (y != u);}
}
signed main() {scanf("%d%d", &n, &m);memset(h, -1, sizeof(h));while (m--) {int a, b;scanf("%d%d", &a, &b);add(a, b);//加入边}for (int i = 1; i <= n; i++) {if (!dfn[i]) tarjan(i); //跑tarjan}for (int i = 1; i <= n; i++) {//枚举每一条边,进行计算每个连通块的出度for (int j = h[i]; ~j; j = ne[j]) {int k = e[j];int a = id[i], b = id[k];//找到这俩个点,看是否在同一个连通块中if (a != b) dout[a]++;//不在的话,因为是有向图,a这个连通块指向b这个连通块就多一条边}}int zeros = 0, sum = 0;  //如果只有一个连通块的出度为0,代表这个连通块之外的所有点都能走到它//如果有俩个及以上连通块出度为0,就代表本题的答案是0for (int i = 1; i <= scc_cnt; i++) {if (!dout[i]) {zeros++;       //记录连通出度为0的数量sum += id_size[i];//加上连通块里面点的数量if (zeros > 1) {sum=0;break;}}}printf("%d\n", sum);return 0;
}

受欢迎的牛(有向图的强连通分量)相关推荐

  1. bzoj1051: [HAOI2006]受欢迎的牛(tarjan强连通分量)

    强连通缩下点,出度为0有多个答案为0,否则答案为出度为0的强连通分量中点的个数. 发现一道tarjan模板题,顺便复习一波tarjan #include<iostream> #includ ...

  2. 算法提高课-图论-有向图的强连通分量-AcWing 1174. 受欢迎的牛:tarjan算法求强连通分量、tarjan算法板子、强连通图

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 强连通图:给定一张有向图.若对于图中任意两个结点x,y,既存在从x到y的路径,也存在从y到x的路径,则称该有向图是"强连通 ...

  3. 算法提高课-图论-有向图的强连通分量-AcWing 367. 学校网络:强连通分量、tarjan算法

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 第一问:通过tarjan算法求出强连通分量并且缩点后,统计入度为0的点的个数p即可. 第二问,至少加几条边才能使图变成强连通分量?这 ...

  4. 有向图的强连通分量(SCC)

    有向图的强连通分量(SCC) 1. 有向图的强连通分量原理 原理 强连通分量是针对有向图来说的.如下的讲解默认都是针对有向图的. 连通分量:对于一个有向图中的一些点来说,如果任意两点都能相互到达,则称 ...

  5. 【图论】—— 有向图的强连通分量

    给定有向图 ,若存在 ,满足从 出发能到达 中所有的点,则称 是一个"流图"( Flow Graph ),记为  ,其中, 称为流图的源点. 在一个流图  上从  进行深度优先遍历 ...

  6. Tarjan 求有向图的强连通分量

    Tarjan 算法与有向图的连通性 Tarjan 算法是基于对图进行深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个栈,回溯时可以判断栈顶到栈中的节点 ...

  7. C++Kosaraju找有向图的强连通分量算法(附完整源码)

    C++Kosaraju找有向图的强连通分量算法 C++Kosaraju找有向图的强连通分量算法完整源码(定义,实现,main函数测试) C++Kosaraju找有向图的强连通分量算法完整源码(定义,实 ...

  8. 缩点(有向图的强连通分量)学习笔记

    缩点(有向图的强连通分量)学习笔记 1.什么是强连通分量?: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路 ...

  9. 有向图的强连通分量,割点与桥

    有向图的强连通分量 1.Tarjan /* Tarjan算法 复杂度O(N+M) */ #include<iostream> #include<stdio.h> #includ ...

  10. 求无向图的连通分量或有向图的强连通分量—tarjan()ccf高速公路

    概念定义: 在图论中,连通图基于连通的概念. 1. 连通(无向图): 若顶点Vi能通过路径到达Vj,那么称为Vi和Vj是连通的 对无向图:若从顶点Vi到顶点Vj有路径相连(当然从j到i也一定有路径), ...

最新文章

  1. oracle 如何预估将要创建的索引的大小
  2. OSPF虚拟链路实验
  3. 趣学python3(46)--求素数
  4. 在Ubuntu14.04上安装UberWriterMarkdown编辑器
  5. R语言观察日志(part21)--包的组件之元数据
  6. 八大排序算法的python实现(三)冒泡排序
  7. 被字句15个_文旅部重新认定国级非遗保护单位,潮州15项花落谁家?这些非遗你都认得吗?...
  8. 计算机d盘不显示容量,电脑D盘可用空间小,可是看不到文件
  9. 如何获得CSDN深色模式(基于Edge的强制深色获取)
  10. 『优势特征知识蒸馏』在淘宝推荐中的应用
  11. AE 将地图导出为图片的两种方法
  12. Matlab排序函数
  13. Unity资源热更-Addressables总结(一)
  14. tp php websocket教程,tp6 websocket方法详解
  15. 同步电机模型的MATLAB仿真模型
  16. Android NDK-EGL 初级
  17. 基于微服务的个人博客系统
  18. matlab编写二分法程序,我写的程序,想用Matlab二分法实现,望高手帮忙!
  19. 基于LSTM模型的共享自行车需求预测
  20. Python中的解包用法

热门文章

  1. 阿里云国际站:阿里云服务器遇到了CC攻击怎么处理防护措施?
  2. 【转】详解4G内存与CPU,BIOS和操作系统之间的牵绊
  3. poi word表格系列操作
  4. 【学习档案】word文档转为XML格式
  5. iOS如何完成蓝牙打印机功能
  6. 王者荣耀s10服务器维护,王者荣耀s9维护到几点?王者荣耀s10赛季上线时间分享...
  7. 《重构-改善既有代码的设计》第三章(上)
  8. 工具(6): 开发神器
  9. Java接口,多态,向上转型,向下转型的意义
  10. Direct3D初始化失败的原因