强连通分量(kosaraju)
2015-07-30 12:22
246 查看
强连通分量特点
1.有向图
2.强连通分量中任意2个点可以互达
3.在一个非强连通图中极大的强连通子图就是该图的强连通分量
4.一个非强连通图可以有多个强连通分量
kosaraju算法
事实:置换图(将图中的边的方向换向)和原始图有相同的强连通分量
描述:
1.首先使G为一个有向图,并且S是一个空栈
2.while S非空:任意选择一个不在栈S中的顶点。从这个顶点v出发运行一个DFS(深搜). 每次dfs扩展到一个顶点u,就将u压入栈S(按照深搜顺序将点编号)
3.反向图G中所有的边获取一个置换图
4. while S非空:取出栈顶元素v. 从v开始运行一个DFS. 访问的结点组成了一个包含v在内的强连通分量,记录,然后从图G和栈S中去掉这些顶点。同样的,BFS也可以来做。
注意:
第一次深搜的时候从搜索头开始编号,最后编号的为搜索点,第二次深搜的时候先增加点再开始搜索其余点
具体见
int ord[maxn];//正向搜索,顶点的编号
bool vis[maxn];//标记顶点是否遍历过
int out[maxn];//转化为DAG以后的每个缩点的出度
int belong[maxn];//当前顶点属于哪个集合,相当于染色,当前顶点被染成了什么颜色
int ans[maxn];//每种颜色包括多少顶点,也就是强联通分量点的个数
int color;//代表不同的颜色,即不同的联通分量
int no;//正向搜索排序的编号(1---n)
int n,m;//顶点数和边数
vector<int> g[maxn],gre[maxn];//存储正向图和逆图
void dfs1(int u)//从当前u顶点开始DFS
{
vis[u] = 1;
for(int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
if(!vis[v]) dfs1(v);
}
ord[no++]=u;//为每个顶点编号
}
void dfs2(int u)
{
vis[u] = 1;
belong[u] = color;//当前顶点u被染成了color
for(int i = 0; i < gre[u].size(); i++)
{
int v = gre[u][i];
if(!vis[v])
{
ans[color]++;
dfs2(v);
}
}
}
int kosaraju()//若仅有1个连通分量的出度为0,返回出度为0的那个连通分量的点的个数
{
color = 1,no = 1;
for(int i = 1; i <= n; i++)//初始化每个点为1个联通分量,即联通分量的点的个数为1
ans[i]=1;
memset(out,0,sizeof(out));//初始化每个联通分量的出度
memset(vis,0,sizeof(vis));
for(int i = 1; i <= n; i++)//搜索每个连通分量并对其进行正序搜索编号
if(!vis[i]) dfs1(i);
memset(vis,0,sizeof(vis));//一定要再次进行遍历初始化
for(int i = no-1; i >= 1; i--)//编好号以后,从排号最大的开始搜索
{
int v = ord[i];//最后入栈的点
if(!vis[v])
{
dfs2(v);
color++;//记录联通分量个数
}
}
//构造DAG
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < g[i].size(); j++)
{
if(belong[i] == belong[g[i][j]]) //若2个点属于同一个联通分量
continue;
out[belong[i]]++;//若有边相连的2个点不是同一个联通分量,则该联通分量的出度+1
}
}
//查找每种颜色出度为0的点或缩点,out[i]代表第i种颜色的点或缩点的出度,出度为0唯一,输出该颜色集合中点的个数ans[i],否则输出0
int ret = 0;//记录出度为0的联通分量的点的个数,若有多于2个联通分量的出度为0,表示此图不连通
int cnt = 0;//记录出度为0的点个数,若出度为0的联通分量只有1个,即被其他点连通的点的个数为该联通分量的点数
for(int i = 1;i < color; i++)//联通分量的个数
{
if(!out[i])//若出度为0
{
cnt++;
ret = ans[i];
}
if(cnt == 2)//这两个if不能写颠倒,切记啊!
{
ret = 0;
break;
}
}
return ret;
}
1.有向图
2.强连通分量中任意2个点可以互达
3.在一个非强连通图中极大的强连通子图就是该图的强连通分量
4.一个非强连通图可以有多个强连通分量
kosaraju算法
事实:置换图(将图中的边的方向换向)和原始图有相同的强连通分量
描述:
1.首先使G为一个有向图,并且S是一个空栈
2.while S非空:任意选择一个不在栈S中的顶点。从这个顶点v出发运行一个DFS(深搜). 每次dfs扩展到一个顶点u,就将u压入栈S(按照深搜顺序将点编号)
3.反向图G中所有的边获取一个置换图
4. while S非空:取出栈顶元素v. 从v开始运行一个DFS. 访问的结点组成了一个包含v在内的强连通分量,记录,然后从图G和栈S中去掉这些顶点。同样的,BFS也可以来做。
注意:
第一次深搜的时候从搜索头开始编号,最后编号的为搜索点,第二次深搜的时候先增加点再开始搜索其余点
具体见
int ord[maxn];//正向搜索,顶点的编号
bool vis[maxn];//标记顶点是否遍历过
int out[maxn];//转化为DAG以后的每个缩点的出度
int belong[maxn];//当前顶点属于哪个集合,相当于染色,当前顶点被染成了什么颜色
int ans[maxn];//每种颜色包括多少顶点,也就是强联通分量点的个数
int color;//代表不同的颜色,即不同的联通分量
int no;//正向搜索排序的编号(1---n)
int n,m;//顶点数和边数
vector<int> g[maxn],gre[maxn];//存储正向图和逆图
void dfs1(int u)//从当前u顶点开始DFS
{
vis[u] = 1;
for(int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
if(!vis[v]) dfs1(v);
}
ord[no++]=u;//为每个顶点编号
}
void dfs2(int u)
{
vis[u] = 1;
belong[u] = color;//当前顶点u被染成了color
for(int i = 0; i < gre[u].size(); i++)
{
int v = gre[u][i];
if(!vis[v])
{
ans[color]++;
dfs2(v);
}
}
}
int kosaraju()//若仅有1个连通分量的出度为0,返回出度为0的那个连通分量的点的个数
{
color = 1,no = 1;
for(int i = 1; i <= n; i++)//初始化每个点为1个联通分量,即联通分量的点的个数为1
ans[i]=1;
memset(out,0,sizeof(out));//初始化每个联通分量的出度
memset(vis,0,sizeof(vis));
for(int i = 1; i <= n; i++)//搜索每个连通分量并对其进行正序搜索编号
if(!vis[i]) dfs1(i);
memset(vis,0,sizeof(vis));//一定要再次进行遍历初始化
for(int i = no-1; i >= 1; i--)//编好号以后,从排号最大的开始搜索
{
int v = ord[i];//最后入栈的点
if(!vis[v])
{
dfs2(v);
color++;//记录联通分量个数
}
}
//构造DAG
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < g[i].size(); j++)
{
if(belong[i] == belong[g[i][j]]) //若2个点属于同一个联通分量
continue;
out[belong[i]]++;//若有边相连的2个点不是同一个联通分量,则该联通分量的出度+1
}
}
//查找每种颜色出度为0的点或缩点,out[i]代表第i种颜色的点或缩点的出度,出度为0唯一,输出该颜色集合中点的个数ans[i],否则输出0
int ret = 0;//记录出度为0的联通分量的点的个数,若有多于2个联通分量的出度为0,表示此图不连通
int cnt = 0;//记录出度为0的点个数,若出度为0的联通分量只有1个,即被其他点连通的点的个数为该联通分量的点数
for(int i = 1;i < color; i++)//联通分量的个数
{
if(!out[i])//若出度为0
{
cnt++;
ret = ans[i];
}
if(cnt == 2)//这两个if不能写颠倒,切记啊!
{
ret = 0;
break;
}
}
return ret;
}
相关文章推荐
- FAQ13715][Gallery] 如何修改gallery的背景色
- UART(接收部分)
- scrollview嵌套listview效果
- 使用genymotion和chares网络调试设置代理方法
- 在线代码格式化工具
- 为GridView添加HeaderView
- 微软提供的android模拟器
- Windows 10 全球发布会精彩瞬间回顾
- Python利用正则表达式匹配并截取指定子串及去重的方法
- EularProject 39:给周长判断构成直角三角形个数
- 获取基目录,它由程序集冲突解决程序用来探测程序集
- html及css学习笔记_12_css三种使用方式
- android 安装与ADT安装
- ios
- 本周周报
- cocos2dx 如何把文件保存到本地
- mysql分组后取前几条数据
- iframe 自适应高度和宽度
- 检索 COM 类工厂中 CLSID 为 {E5FF9F62-0E7C-4372-8AD5-DA7D2418070C} 的组件时失败,原因是出现以下错误: 80040154。
- 【asp】 SQLServer OLEDB 连接数据库 代码