什么是强连通分量?在这之前先定义一个强连通性(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. CTF两个经典的文件包含案例

    案例一URL:http://120.24.86.145:8003/代码 <?php include "waf.php"; include "flag.php&quo ...

  2. mac os x 把reids nignx mongodb做成随机启动吧

    ~/Library/LaunchAgents 由用户自己定义的任务项 /Library/LaunchAgents 由管理员为用户定义的任务项 /Library/LaunchDaemons 由管理员定义 ...

  3. sicily 1016. 排队接水--课程作业

                                                                                    1016. 排队接水 Time Limi ...

  4. Python爬虫音频数据

    一:前言 本次爬取的是喜马拉雅的热门栏目下全部电台的每个频道的信息和频道中的每个音频数据的各种信息,然后把爬取的数据保存到mongodb以备后续使用.这次数据量在70万左右.音频数据包括音频下载地址, ...

  5. CentOS下配置FTP

    http://www.cnblogs.com/zhenmingliu/archive/2012/04/25/2470646.html 常见错误: 1.FTP服务器已经拒绝 解决方案 # setenfo ...

  6. node起server--axios做前端请求----进行CORS--跨域请求

    CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing). 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从 ...

  7. 详解java中的TreeSet集合

    TreeSet是实现Set接口的实现类.所以它存储的值是唯一的,同时也可以对存储的值进行排序,排序用的是二叉树原理.所以要理解这个类,必须先简单理解一下什么是二叉树. 二叉树原理简述 假如有这么一个集 ...

  8. Html Css  练习

    一.  取消a链接的下划线 <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...

  9. LightOJ - 1370

    Bi-shoe and Phi-shoe Time Limit: 2000MS   Memory Limit: 32768KB   64bit IO Format: %lld & %llu S ...

  10. 利用WINDOWS活动目录提供LDAP的方案

    Windows Server 2008 R2 活动目录服务安装 http://blog.sina.com.cn/s/blog_622de9390100kgv3.html WINDOWS 2008 域控 ...