什么是强连通分量?在这之前先定义一个强连通性(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. setsockopt 详解

    1. closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket: BOOL bReuseaddr=TRUE; setsockopt(s,SOL_SOCKET  ...

  2. Vue组件-组件的属性

    在html中使用元素,会有一些属性,如class,id,还可以绑定事件,自定义组件也是可以的.当在一个组件中,使用了其他自定义组件时,就会利用子组件的属性和事件来和父组件进行数据交流. 比如,子组件需 ...

  3. win7下安装Linux实现双系统全攻略

    http://jingyan.baidu.com/article/c275f6bacc3326e33c756743.html

  4. Jmeter===Jmeter中使用CSV Data Set Config参数化不重复数据执行N遍(转)

    Jmeter中使用CSV Data Set Config参数化不重复数据执行N遍 要求: 今天要测试上千条数据,且每条数据要求执行多次,(模拟多用户多次抽奖) 1.用户id有175个,且没有任何排序规 ...

  5. 2015多校第8场 HDU 5382 GCD?LCM! 数论公式推导

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5382 题意:函数lcm(a,b):求两整数a,b的最小公倍数:函数gcd(a,b):求两整数a,b的最 ...

  6. linux命令(45):diff命令

    1.命令格式: diff[参数][文件1或目录1][文件2或目录2] 2.命令功能: diff命令能比较单个文件或者目录内容.如果指定比较的是文件,则只有当输入为文本文件时才有效.以逐行的方式,比较文 ...

  7. Django 1.6在Windows平台下的配置

    Django 1.6 在Windows平台下的配置 前言 最近两天研究了下Django1.6在Windows平台中的配置安装,服务器采用Apache.期间遇到过许多新手所遇到的各种问题,也算是一种宝贵 ...

  8. Linux下几个命令的技巧

    Ctrl的组合键+a,移动到一行命令的首部+e,移动到一行命令的尾部+左右键,以单词为单位左右移动+u,删除光标之前的所有内容+k,删除光标之后的所有内容Alt+.为引用上一个命令的最后一个参数 还有 ...

  9. vmware + ubuntu 64 安装 node.js v8.9.3

    第一次使用虚拟机,第一次使用linux系统,第一次安装使用node.js 虚拟机安装不用多说,安装好之后下载ubuntu 64位版本文件 在vm中点击“创建新的虚拟机”,选择下载的ubuntu iso ...

  10. Centos7使用squid实现正向代理

    正向代理:代理服务器帮助客户端(浏览器)实现互联网的访问 (1)代理服务器配置 1.安装squid yum install squid -y 2.编辑squid配置文件 #vim /etc/squid ...