解决有向图的强连通分量的算法,有两个,一个是tarjan,一个是kosaraju,上午只看了一下kosaraju,不算太难,理解之后写了个模板题。

先说kosaraju算法,算法的主要思路是进行两次dfs,一次是正向边,一次是反向边,在时间复杂度O(V+E)之下便可统计出有多少个强连通分量以及每个点所属的强连通分量编号。

下面说一次具体实现过程及正确性,假设一副有向图G,他一定是由若干个强连通分量所构成的,这些强连通分量之间可以有边连接,但是边的方向一定是相同的,否则这两个连通分量可以合并为一个强连通分量。我们将每个scc看作一个点的话,图G就转化为了一个DAG。我们在第一次正向dfs时候对点进行逆序标记,这样的话标号最大的点一定位于这个DAG的起点,接下来将边反向,对于scc内部的点显然没影响,只是DAG的方向变了,此时从标号大的点开始搜索,能一次访问到的点一定位于同一个scc!至此算法结束。

1332 上白泽慧音

http://codevs.cn/problem/1332/

时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
 
 
 
题目描述 Description

在幻想乡,上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点。人间之里由N个村庄(编号为1..N)和M条道路组成,道路分为两种一种为单向通行的,一种为双向通行的,分别用1和2来标记。如果存在由村庄A到达村庄B的通路,那么我们认为可以从村庄A到达村庄B,记为(A,B)。当(A,B)和(B,A)同时满足时,我们认为A,B是绝对连通的,记为<A,B>。绝对连通区域是指一个村庄的集合,在这个集合中任意两个村庄X,Y都满足<X,Y>。现在你的任务是,找出最大的绝对连通区域,并将这个绝对连通区域的村庄按编号依次输出。若存在两个最大的,输出字典序最小的,比如当存在1,3,4和2,5,6这两个最大连通区域时,输出的是1,3,4。

输入描述 Input Description

第1行:两个正整数N,M

第2..M+1行:每行三个正整数a,b,t, t = 1表示存在从村庄a到b的单向道路,t = 2表示村庄a,b之间存在双向通行的道路。保证每条道路只出现一次。

输出描述 Output Description

第1行: 1个整数,表示最大的绝对连通区域包含的村庄个数。

第2行:若干个整数,依次输出最大的绝对连通区域所包含的村庄编号。

样例输入 Sample Input

5 5

1 2 1

1 3 2

2 4 2

5 1 2

3 5 1

样例输出 Sample Output

3

1 3 5

数据范围及提示 Data Size & Hint

对于60%的数据:N <= 200且M <= 10,000

对于100%的数据:N <= 5,000且M <= 50,000

分类标签 Tags 点此展开

 #include<bits/stdc++.h>
using namespace std;
struct Edge
{
int v,next;
}e1[],e2[];
int first1[],first2[];
int tot1,tot2;
bool vis[];
int f[];
int tot[];
vector<int>vi;
void add1(int u,int v){
e1[tot1].v=v;
e1[tot1].next=first1[u];
first1[u]=tot1++;
}
void add2(int u,int v){
e2[tot2].v=v;
e2[tot2].next=first2[u];
first2[u]=tot2++;
}
void dfs1(int u){
vis[u]=;
for(int i=first1[u];~i;i=e1[i].next){
int v=e1[i].v;
if(vis[v]) continue;
dfs1(v);
}
vi.push_back(u);
}
int dfs2(int u,int k){
vis[u]=;
f[u]=k;
int s=;
for(int i=first2[u];~i;i=e2[i].next){
int v=e2[i].v;
if(vis[v]) continue;
s+=dfs2(v,k);
}
return s;
} int main()
{
int N,M,i,j,k,u,v,t,w;
while(cin>>N>>M){
vi.clear();
memset(first1,-,sizeof(first1));
memset(first2,-,sizeof(first2));
memset(vis,,sizeof(vis));
memset(tot,,sizeof(tot));
tot1=tot2=;
for(i=;i<=M;++i){
scanf("%d%d%d",&u,&v,&t);
add1(u,v);
add2(v,u);
if(t==){
add1(v,u);
add2(u,v);
}
}
for(i=;i<=N;++i){
if(!vis[i]) dfs1(i);
}
memset(vis,,sizeof(vis));
k=;
int maxk=;
for(i=N-;i>=;--i){
if(!vis[vi[i]]) maxk=max(maxk,dfs2(vi[i],++k));
}
cout<<maxk<<endl;
for(i=;i<=N;++i) tot[f[i]]++;
for(i=;i<=N;++i){
if(maxk==tot[f[i]]) {maxk=f[i];break;}
}
for(i=;i<=N;++i){
if(f[i]==maxk){
cout<<i;
break;
}
}
i++;
for(;i<=N;++i){
if(f[i]==maxk)
printf(" %d",i);
}
puts("");
}
return ;
}

强连通分量算法-codevs1332的更多相关文章

  1. 强连通分量算法·$tarjan$初探

    嗯,今天好不容易把鸽了好久的缩点给弄完了--感觉好像--很简单? 算法的目的,其实就是在有向图上,把一个强连通分量缩成一个点--然后我们再对此搞搞事情,\(over\) 哦对,时间复杂度很显然是\(\ ...

  2. Tarjan的强连通分量算法

    Tarjan算法用于寻找图G(V,E)中的所有强连通分量,其时间复杂度为O(|V|+|E|). 所谓强连通分量就是V的某个极大子集,其中任意两个结点u,v在图中都存在一条从u到v的路径. Tarjan ...

  3. 图之强连通、强连通图、强连通分量 Tarjan算法

    原文地址:https://blog.csdn.net/qq_16234613/article/details/77431043 一.解释 在有向图G中,如果两个顶点间至少存在一条互相可达路径,称两个顶 ...

  4. 有向图强连通分量Tarjan算法

    在https://www.byvoid.com/zhs/blog/scc-tarjan中关于Tarjan算法的描述非常好,转述如下: 首先解释几个概念: 有向图强连通分量:在有向图G中,如果两个顶点间 ...

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

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

  6. 模板 - 图论 - 强连通分量 - Kosaraju算法

    这个算法是自己实现的Kosaraju算法,附带一个缩点,其实缩点这个跟Kosaraju算法没有什么关系,应该其他的强连通分量算法计算出每个点所属的强连通分量之后也可以这样缩点. 算法复杂度: Kosa ...

  7. 浅析强连通分量(Tarjan和kosaraju)

    理解   在有向图G中,如果两点互相可达,则称这两个点强连通,如果G中任意两点互相可达,则称G是强连通图. 定理: 1.一个有向图是强连通的,当且仅当G中有一个回路,它至少包含每个节点一次.     ...

  8. tarjan 强连通分量

    一.强连通分量定义 有向图强连通分量在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly c ...

  9. poj 2762 Going from u to v or from v to u?【强连通分量缩点+拓扑排序】

    Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15812 ...

随机推荐

  1. javascript 类型 内存 对象

    var box =0 function test() { alert(box) //全局 }

  2. MySql—模糊查询

    实例: SQL模糊查询,使用like比较关键字,加上SQL里的通配符,请参考以下:  1.LIKE 'Mc%' 将搜索以字母 Mc 开头的所有字符串(如 McBadden).  2.LIKE '%in ...

  3. shell脚本批量启动zookeeper

    脚本名称为zk_run.sh 将下面代码粘贴进zk_run.sh 添加执行权限 chmode +x zk_run.sh 运行脚本 ./zk_run.sh start 如果发现zookeeper没有启动 ...

  4. Dbus组成和原理

    DBUS是实质上一个适用于桌面应用的进程间的通讯机制,即所谓的IPC机制.适合在同一台机器,不适合于INTERNET的IPC机制.DBUS不是一个为所有可能的应用的通用的IPC机制,不支持其他IPC机 ...

  5. Python面试题之Python反射机制

    0x00 前言 def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') def f4(): print('f4') a = ...

  6. iframe的应用量还是这么大

    以前查阅资料说iframe已经过时,不建议使用,可是在先进的2018年,你去随便打开一个网站,扔都可以见到iframe的身影,这不禁要发问:iframe的应用量为什么还是这么大? HTML5不再支持使 ...

  7. CentOS修改时区、日期、时间

    一.时区 显示时区 date --help 获取帮助 date -R date +%z 修改时区 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ...

  8. linux c开发环境构成

    1.编辑器:VI.VIM 2.编译器:GNU C/C++编译器gcc 3.调试器:gdb 4.函数库:glibc 5.系统头文件:glibc_header

  9. java处理json的工具类(list,map和json的之间的转换)

    需要下载第三方的jar :net.sf.json import java.io.BufferedReader; import java.io.InputStream; import java.io.I ...

  10. Centos7 Python3.x源码安装

    第一步,安装开发工具集 yum -y groupinstall "Development tools" 第二步,安装相关依赖包: yum -y install zlib-devel ...