什么是强连通分量?在这之前先定义一个强连通性(strong connectivity)的概念:有向图中,如果一个顶点s到t有一条路径,t到s也有一条路径,即s与t互相可达,那么我们说s与t是强连通的。那么在有向图中,由互相强连通的顶点构成的分量,称作强连通分量。

一:对于kosaraju算法,这是一个比tarjan较复杂的算法,但是因为一本通上介绍了这种算法,我就找几个题目练习了一下。

kosaraju算法:可以求出强连通分量的个数,还可以对分属于不同强连通分量的点进行标记。

算法描述:(1):第一次对图G进行DFS遍历,并在遍历的过程中,记录每一个点的退出顺序。

(2):倒转每一条边的方向,构造一个反图G1,然后按照退出的顺序的逆序对反图进行第二次DFS遍历,

(3):每一次遍历得到的那些点属于同一个强连通分量。

因为这就是一个不变的模板,所以直接背过就是最好了

例题:

1298. 通讯问题(来源:sojs.tk)

★   输入文件:jdltt.in   输出文件:jdltt.out   简单对比
时间限制:1 s   内存限制:128 MB

【题目描述】

一个篮球队有n个篮球队员,每个队员都有联系方式(如电话、电子邮件等)。但并不是每个队员的联系方式都公开,每个队员的联系方式只有一部分队员知道。问队员可以分成多少个小组,小组成员之间可以相互通知(包括一个队员一个组,表示自己通知自己)。

【输入格式】

输入文件有若干行

第一行,一个整数n,表示共有n个队员(2<=n<=100)

下面有若干行,每行2个数a、b,a、b是队员编号,表示a知道b的通讯方式。

【输出格式】

输出文件有若干行

第一行,1个整数m,表示可以分m个小组,下面有m行,每行有若干个整数,表示该小组成员编号,输出顺序按编号由小到大。

【样例输入】

12
1 3
2 1
2 4
3 2
3 4
3 5
4 6 
5 4
6 4
7 4 
7 8
7 12
8 7
8 9
10 9
11 10 

【样例输出】

8

1 2 3

4 6

5

7 8

9

10

11

12

这道题目的输出顺序是很坑的。

#include<iostream>
using namespace std;
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<stack>
#define N 120
struct Edge{
int u,v,last;
}edge1[N],edge2[N];
int t=;
stack<int>s;
int ans[N][N];
int pp=;
int head1[N]={},head2[N]={};
bool visit[N]={};
int n;
void input()
{
scanf("%d",&n);
int a,b;
while(scanf("%d%d",&a,&b)==)
{
++t;
edge1[t].u=a;
edge1[t].v=b;
edge1[t].last=head1[a];
head1[a]=t;
edge2[t].u=b;
edge2[t].v=a;
edge2[t].last=head2[b];
head2[b]=t; } }
void dfs1(int k)
{
visit[k]=true;
for(int l=head1[k];l;l=edge1[l].last)
{
if(!visit[edge1[l].v])
{
dfs1(edge1[l].v);
}
}
s.push(k);
}
void dfs2(int k)
{
ans[pp][]++;
ans[pp][ans[pp][]]=k;
visit[k]=true;
for(int l=head2[k];l;l=edge2[l].last)
{
if(!visit[edge2[l].v])
{
dfs2(edge2[l].v);
}
}
}
int kosaraju()
{
while(!s.empty())
s.pop();
memset(visit,false,sizeof(visit));
for(int i=;i<=n;++i)
{
if(!visit[i])
dfs1(i);
}
memset(visit,false,sizeof(visit));
while(!s.empty())
{
int k=s.top();
s.pop();
if(!visit[k])
{
pp++;
dfs2(k);
}
}
return pp;
}
int main()
{
freopen("jdltt.in","r",stdin);
freopen("jdltt.out","w",stdout);
input();
pp=;
printf("%d\n",kosaraju());
for(int i=;i<=pp;++i)
sort(ans[i]+,ans[i]+ans[i][]+);
bool flag[N]={};
for(int i=;i<=pp;++i)
{
int q=;
int maxx=(<<);
for(int j=;j<=pp;++j)
{
if(maxx>ans[j][]&&!flag[j])
{
maxx=ans[j][];
q=j;
}
}
flag[q]=true;
for(int j=;j<=ans[q][];++j)
printf("%d ",ans[q][j]);
printf("\n");
}
fclose(stdin);
fclose(stdout);
return ;
}

例题二:

619. [金陵中学2007] 传话(来源cojs.tk)

★☆   输入文件:messagez.in   输出文件:messagez.out   简单对比
时间限制:1 s   内存限制:128 MB

[问题描述]

兴趣小组的同学来自各个学校,为了增加友谊,晚会上又进行了一个传话游戏,如果 a 认识 b ,那么 a 收到某个消息,就会把这个消息传给 b ,以及所有 a 认识的人。

如果 a 认识 b , b 不一定认识 a 。

所有人从 1 到 n 编号,给出所有“认识”关系,问如果 i 发布一条新消息,那么会不会经过若干次传话后,这个消息传回给了 i , 1<=i<=n 。

[输入文件]

输入文件 message.in 中的第一行是两个数 n(n<1000) 和 m(m<10000) ,两数之间有一个空格,表示人数和认识关系数。

接下来的 m 行,每行两个数 a 和 b ,表示 a 认识 b 。 1<=a, b<=n 。认识关系可能会重复给出,但一行的两个数不会相同。

[输出文件]

输出文件 message.out 中一共有 n 行,每行一个字符 T 或 F 。第 i 行如果是 T ,表示 i 发出一条新消息会传回给 i ;如果是 F ,表示 i 发出一条新消息不会传回给 i 。

[输入样例]

4 6
1 2 
2 3 
4 1 
3 1 
1 3 
2 3

[输出样例]




F

思路:仍然是求强连通分量,只是要判断每一个人是否在一个人数>=2的强连通分量中,如果是就满足题目条件

代码:

#include<iostream>
using namespace std;
#include<cstdio>
int n,m,a,b;
struct Edge{
int u,v,last;
};
int t=;
#include<stack>
#define M 10020
Edge edge1[M],edge2[M];
#define N 1008
stack<int> s;
int head1[N],head2[N];
bool visit[N];
#include<algorithm>
#include<cstring>
bool flag[N]={};
int ans[N][N];
int calc=;
void input()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;++i)
{
scanf("%d%d",&a,&b);
++t;
edge1[t].u=a;
edge1[t].v=b;
edge1[t].last=head1[a];
head1[a]=t;
edge2[t].u=b;
edge2[t].v=a;
edge2[t].last=head2[b];
head2[b]=t; }
}
void dfs1(int k)
{
visit[k]=true;
for(int p=head1[k];p;p=edge1[p].last)
{
if(!visit[edge1[p].v])
dfs1(edge1[p].v);
}
s.push(k);
}
void dfs2(int k)
{
int flat=calc;
visit[k]=true;
ans[calc][]++;
ans[calc][ans[calc][]]=k;
for(int p=head2[k];p;p=edge2[p].last)
if(!visit[edge2[p].v])
{ dfs2(edge2[p].v);
}
if(ans[flat][]>)/*判断每一个人是否在一个人数>=2的强连通分量*/
flag[k]=true;
}
void kosaraju()
{
while(!s.empty())
s.pop();
memset(visit,false,sizeof(visit));
for(int i=;i<=n;++i)
{
if(!visit[i])
dfs1(i);
}
memset(visit,,sizeof(visit));
while(!s.empty())
{
int k=s.top();
s.pop();
if(!visit[k])
{
calc++;
dfs2(k);
}
}
}
int main()
{
freopen("messagez.in","r",stdin);
freopen("messagez.out","w",stdout);
input();
kosaraju();
for(int i=;i<=n;++i)
if(flag[i])
printf("T\n");
else printf("F\n");
fclose(stdin);
fclose(stdout);
return ;
}

kosaraju算法求强连通分量的更多相关文章

  1. Tarjan 算法求 LCA / Tarjan 算法求强连通分量

    [时光蒸汽喵带你做专题]最近公共祖先 LCA (Lowest Common Ancestors)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili tarjan LCA - YouTube Tarj ...

  2. HDU 1269 迷宫城堡 tarjan算法求强连通分量

    基础模板题,应用tarjan算法求有向图的强连通分量,tarjan在此处的实现方法为:使用栈储存已经访问过的点,当访问的点离开dfs的时候,判断这个点的low值是否等于它的出生日期dfn值,如果相等, ...

  3. [学习笔记] Tarjan算法求强连通分量

    今天,我们要探讨的就是--Tarjan算法. Tarjan算法的主要作用便是求一张无向图中的强连通分量,并且用它缩点,把原本一个杂乱无章的有向图转化为一张DAG(有向无环图),以便解决之后的问题. 首 ...

  4. tarjan算法求强连通分量

    先上代码: #include <iostream> #include <cstring> #include <vector> #include <stack& ...

  5. 【算法】Tarjan算法求强连通分量

    概念: 在有向图G中,如果两个定点u可以到达v,并且v也可以到达u,那么我们称这两个定点强连通. 如果有向图G的任意两个顶点都是强连通的,那么我们称G是一个强连通图. 一个有向图中的最大强连通子图,称 ...

  6. tarjan 算法求强连通分量

    #include<bits/stdc++.h> #define ll long long using namespace std; const int P=1e6; ; ; const i ...

  7. Tarjan算法打包总结(求强连通分量、割点和Tarjan-LCA)

    目录 Tarjan打包总结(求强连通分量.割点和Tarjan-LCA) 强连通分量&缩点 原理 伪代码 板子(C++) 割点 原理 伪代码 最近公共祖先(LCA) 原理 伪代码 板子 Tarj ...

  8. 求强连通分量模板(tarjan算法)

    关于如何求强连通分量的知识请戳 https://www.byvoid.com/blog/scc-tarjan/ void DFS(int x) { dfn[x]=lowlink[x]=++dfn_cl ...

  9. Tarjan算法分解强连通分量(附详细参考文章)

    Tarjan算法分解强连通分量 算法思路: 算法通过dfs遍历整个连通分量,并在遍历过程中给每个点打上两个记号:一个是时间戳,即首次访问到节点i的时刻,另一个是节点u的某一个祖先被访问的最早时刻. 时 ...

随机推荐

  1. STM32接口FSMC/FMC难点详解

    STM32接口FSMC/FMC难点详解 转载   http://blog.sina.com.cn/s/blog_808bca130102x94k.html STM32F767的FMC将外部存储器划分为 ...

  2. MHA切换过程:

    1.监测master的状态Ping(SELECT) succeeded, waiting until MySQL doesn't respond.. 2.当监控发现master异常时发出warning ...

  3. docker数据管理--数据卷的备份

    /* 先在宿主机创建一个备份的文 件夹, 然后将其以另外一个名字的目录挂载到容器里, 此时不管容器里,或宿主机里做什么操作, 数据都会及时更新,并得到备份. */ [root@localhost ~] ...

  4. 步骤一:下载jdk并安装和配置java环境变量

    1.下载JDk地址: http://download.eclipse.org/oomph/jre/?vm=1_1_7_0_64_0 2.进入下载页面(下载的是jdk7),点击:Oracle JDK1. ...

  5. mysql 库操作、存储引擎、表操作

    阅读目录 库操作 存储引擎 什么是存储引擎 mysql支持的存储引擎 如何使用存储引擎 表操作 创建表 查看表结构 修改表ALTER TABLE 复制表 删除表 数据类型 表完整性约束 回到顶部 一. ...

  6. Edit Distance——经典的动态规划问题

    题目描述Edit DistanceGiven two words word1 and word2, find the minimum number of steps required to conve ...

  7. 微信小程序~触摸相关事件(拖拽操作、手势识别、多点触控)

    touchstart     手指触摸动作开始 touchmove    手指触摸后移动 touchcancel  手指触摸动作被打断,如来电提醒,弹窗 touchend      手指触摸动作结束 ...

  8. 走进 Prism for Xamarin.Forms

    一.使用环境 OS:Win 10 16273 VS:VS2017- 15.3.4 Xamarin:4.6.3.4,nuget:2.4 Android Emulator:Visual Studio fo ...

  9. HBase shell 命令创建表及添加数据操作

    创建表,表名hbase_1102,HBase表是由Key-Value组成的,此表中Key为NAME   此表有两个列族,CF1和CF2,其中CF1和CF2下分别有两个列name和gender,Chin ...

  10. bzoj 1443 二分图博弈

    这种两个人轮流走,不能走 走过的格子的大都是二分图博弈... #include<bits/stdc++.h> #define LL long long #define fi first # ...