定义:有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量。

求强连通分量:

vector<int>pic[maxn];
int dfn[maxn],low[maxn],ans[maxn];
bool ins[maxn];
stack<int>st;
int dind=0,block=0;
int siz[maxn],cud[maxn];
void tarjan(int x)
{dind++;dfn[x]=low[x]=dind;ins[x]=true;st.push(x);for (int j=0;j<pic[x].size();j++){int y=pic[x][j];if (dfn[y]==0){tarjan(y);low[x]=min(low[x],low[y]);}else if (ins[y]) low[x]=min(low[x],dfn[y]);}if (low[x]==dfn[x]){block++;siz[block]=0;while (true){int thi=st.top();st.pop();ans[thi]=block;siz[block]++;ins[thi]=false;if (thi==x) break;}}
}

  例题1【UVA-11324 最大团】

分析:先计算强连通分量,然后建一张新图,每个点的权值是它所包含的点的数量,求图的最长链。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
const int maxn=1010;
vector<int> pic[maxn],new_[maxn];
int dfn[maxn],low[maxn],ans[maxn];
bool ins[maxn];
stack<int>st;
int dind=0,block=0;
int siz[maxn],dp[maxn],Ans;
void tarjan(int x)
{dind++;dfn[x]=low[x]=dind;ins[x]=true;st.push(x);for (int j=0;j<pic[x].size();j++){int y=pic[x][j];if (!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}else if (ins[y]) low[x]=min(low[x],dfn[y]);}if (low[x]==dfn[x]){block++;siz[block]=0;while (true){int thi=st.top();st.pop();ans[thi]=block;siz[block]++;ins[thi]=false;if (thi==x) break;}}
}
int DP(int x){    if(dp[x]!=-1) return dp[x];int Max=0;  for(int i=0;i<new_[x].size();i++)  Max=max(Max,DP(new_[x][i]));  return dp[x]=siz[x]+Max;
}
void init(int n){for(int i=1;i<=n;i++) pic[i].clear(),new_[i].clear();memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low));memset(ans,0,sizeof(ans)); memset(ins,0,sizeof(ins));while(!st.empty()) st.pop(); dind=block=Ans=0;memset(siz,0,sizeof(siz)); memset(dp,-1,sizeof(dp));
}
int main(){int n,m,N,u,v;scanf("%d",&N);while(N--){scanf("%d%d",&n,&m);init(n);while(m--){scanf("%d%d",&u,&v);pic[u].push_back(v);}for(int i=1;i<=n;i++)if(!dfn[i]) tarjan(i);for(int i=1;i<=n;i++)for(int j=0;j<pic[i].size();j++)if(ans[i]!=ans[pic[i][j]]) new_[ans[pic[i][j]]].push_back(ans[i]);for(int i=1;i<=block;i++) Ans=max(Ans,DP(i));printf("%d\n",Ans);}return 0;
}

  例题2【POJ 1236 学校网络】

第一问:缩点后求入度为0的结点数量;

第二问:对于一张有向无环图,可以通过把叶子结点连向根节点使它强连通;

like this:

所以需要连的边数量为max(叶节点,根节点);

叶节点是出度为0的点,根节点是入度为0的点;

注意当只有一个强连通分量时,需要特判,为0;

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<set>
using namespace std;
const int maxn=110;
vector<int> pic[maxn];
int dfn[maxn],low[maxn],ans[maxn];
bool ins[maxn];
stack<int>st;
set<int>check[maxn];
int dind=0,block=0;
int siz[maxn];
int ans1,in[maxn],out[maxn];void tarjan(int x)
{dind++;dfn[x]=low[x]=dind;ins[x]=true;st.push(x);for (int j=0;j<pic[x].size();j++){int y=pic[x][j];if (!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}else if (ins[y]) low[x]=min(low[x],dfn[y]);}if (low[x]==dfn[x]){block++;siz[block]=0;while (true){int thi=st.top();st.pop();ans[thi]=block;siz[block]++;ins[thi]=false;if (thi==x) break;}}
}
int main(){int n,i,j;scanf("%d",&n);for(i=1;i<=n;i++){scanf("%d",&j);while(j) pic[i].push_back(j),scanf("%d",&j);  }for(int i=1;i<=n;i++)if(!dfn[i]) tarjan(i);for (i=1;i<=n;i++)for (j=0;j<pic[i].size();j++){int b1=ans[i],b2=ans[pic[i][j]];if (b1==b2) continue;if (check[b1].count(b2)) continue;check[b1].insert(b2);in[b2]++; out[b1]++;}int root=0,leaf=0;for(int i=1;i<=block;i++){if(!in[i]) root++;if(!out[i]) leaf++;}printf("%d\n",root);if(block==1) printf("0");else printf("%d",max(leaf,root));return 0;
}

  类似的还有【HDU 2767】

很奇怪的是提交时出现了这样尴尬的问题:

0_0_20950778_21662.cpp
0_0_20950778_21662.cpp(29) : error C3861: “min”:  找不到标识符
0_0_20950778_21662.cpp(31) : error C3861: “min”:  找不到标识符
0_0_20950778_21662.cpp(83) : error C3861: “max”:  找不到标识符

然后在出错的库后面加上了#include "minmax.h",就过了?(莫名其妙)

代码:

#include<iostream>
#include "minmax.h"
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<set>
using namespace std;
const int maxn=20010;
vector<int> pic[maxn];
int dfn[maxn],low[maxn],ans[maxn];
bool ins[maxn];
stack<int>st;
set<int>check[maxn];
int dind=0,block=0,siz[maxn];
int in[maxn],out[maxn],T;
void tarjan(int x)
{dind++;dfn[x]=low[x]=dind;ins[x]=true;st.push(x);for (int j=0;j<pic[x].size();j++){int y=pic[x][j];if (!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}else if (ins[y]) low[x]=min(low[x],dfn[y]);}if (low[x]==dfn[x]){block++;siz[block]=0;while (true){int thi=st.top();st.pop();ans[thi]=block;siz[block]++;ins[thi]=false;if (thi==x) break;}}
}
void init(int n){for(int i=1;i<=n;i++)  pic[i].clear(),check[i].clear();;memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low));memset(ans,0,sizeof(ans)); memset(ins,0,sizeof(ins));while(!st.empty()) st.pop(); dind=0;block=0; memset(siz,0,sizeof(siz));memset(in,0,sizeof(in)); memset(out,0,sizeof(out));
}
int main(){scanf("%d",&T);while(T--){int n,i,j,m;scanf("%d%d",&n,&m);init(n);for(i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);pic[x].push_back(y);    }for(int i=1;i<=n;i++)if(!dfn[i]) tarjan(i);for (i=1;i<=n;i++)for (j=0;j<pic[i].size();j++){int b1=ans[i],b2=ans[pic[i][j]];if (b1==b2) continue;if (check[b1].count(b2)) continue;check[b1].insert(b2);in[b2]++; out[b1]++;}int root=0,leaf=0;for(int i=1;i<=block;i++){if(!in[i]) root++;if(!out[i]) leaf++;}if(block==1) printf("0\n");else printf("%d\n",max(leaf,root));}return 0;
}

  ————————————————————————————————————————————————————————

来自Paper Cloud的博客,未经允许,请勿转载,谢谢

转载于:https://www.cnblogs.com/PaperCloud/p/7113385.html

强连通分量(学习心得)相关推荐

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

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

  2. 算法学习:强连通分量 --tarjan

    [定义] [强连通分量] 在一个子图中,任意点能够直接或者间接到达这个子图中的任意点,这个子图被称为强连通分量 [解决问题] 求图的强连通分量 同时能够起到 ...................缩点 ...

  3. 图论专题-学习笔记:强连通分量

    图论专题-学习笔记:强连通分量 一些 update 1. 前言 2. 定义 3. 求法 4. 应用 5. 总结 一些 update update on 2021/8/12:增加了对于 Kosaraju ...

  4. 学习有向图和无向图的强连通分量(基本概念+割点+点双联通分量+桥+边双连通分量+全套模板【Tarjan】)

    最近总是考到Tarjan,让我措手不及 基本概念 割点以及点双连通分量 Tarjan法求割点 推导过程 代码实现 Tarjan法求点双连通分量 推导过程 代码实现 有向图的Tarjan缩点 桥与边双连 ...

  5. 图论学习-有向图强连通分量

    文章目录 有向图强连通分量 1.定义: 2.基本术语与概念 2.1 边的概念 2.2 缩点 2.3 时间戳 3. tarjan求强连通分量(SCC) 3.1 原理 3.2 步骤 3.3 模板 3.3. ...

  6. 图论学习六之Strongly connected components强连通分量

    强连通分量(Strongly connected cmponents) • 在有向图G中,如果任意两个不同的顶点相互可达,则称该有向   图是强连通的.有向图G的极大强连通子图称为<

  7. 强连通分量算法学习笔记

    强连通分量 更好阅读体验请点击此链接 先推荐几道综合性较强的题目,详细题解我写了,持续更新中. 我的博客:整理 + 题解 P2341 [USACO03FALL][HAOI2006]受欢迎的牛 G P2 ...

  8. networkx 有向图强连通_leetcode刷题(四):搜索(深度优先搜索,广度优先搜索)拓扑排序,强连通分量...

    在开始今天的话题之前,我们先了解一个概念,什么是图的遍历? 图的遍历就是从图中某一点出发访遍图中其余剩余定点,且每个顶点仅被访问一次,这个过程叫做图的遍历. 图的遍历主要被分为深度优先遍历和广度优先遍 ...

  9. 极小连通子图和极大连通子图_强连通分量与拓扑排序

    前言 由于GacUI里面开始多处用上拓扑排序,我决定把之前瞎JB搞出来的算法换掉,换成个正式的.之前我自己弄了个写起来很简单的算法,然后每一处需要用到的地方我就重新做一遍.当然这样肯定也是不行的,我觉 ...

最新文章

  1. 运用Handler.post()方法进行数据更新跟用Message对比(18)
  2. 用一条dos命令创建一个恶意文件夹
  3. java表达式语法格式为_2009(选修)JavaWeb模拟试卷(2011-2012)
  4. 这家中国企业和星巴克对着干 年亏16亿却成为全球最快上市公司
  5. 求解集合A与B的差集
  6. 8.19 NOIP模拟测试26(B) 嚎叫响彻在贪婪的厂房+主仆见证了 Hobo 的离别+征途堆积出友情的永恒...
  7. 入门系列之在Ubuntu上使用MySQL设置远程数据库优化站点性能
  8. 根据wsdl文件生成WebService客户端代码
  9. ROUTE ADD 命令详解
  10. bzoj4326 NOIP2015 运输计划
  11. 最近面试有感,不要耍小聪明,面试官都是开了上帝视角的
  12. 多个线程交替打印ABC,打印10次
  13. vue 上传图片进行压缩图片
  14. 分层聚类(Hierarchical clustering)
  15. 端到端和非端到端的Embedding,以及embedding质量评估
  16. Python人工智能学习路线(长篇干货)
  17. 由浅入深学习android input系统(五) - input系统的启动
  18. PDF Forte Pro(PDF转换器)v3.1.2免费版
  19. 论文写作-调研如何去写你的论文
  20. Thinkpad x60 Bios设置指南

热门文章

  1. button按钮onclick触发不了_单按钮启停:测试模拟脉冲发生器的动作
  2. linux 下停止监听程序,Linux下启动Oracle服务和监听程序步骤
  3. Mysql - 安装与配置
  4. Flexbox 布局
  5. js 实现 复制 功能 (zeroclipboard)
  6. 修改Visual Stdio 2010界面,以及添加一些其它VS2010的插件
  7. 用“Web的思想”做PC客户端
  8. 面试官: 用css实现android系统的loading动画
  9. linux shell命令行选项与参数用法详解
  10. GRE Sub math 报名