codevs1506传话(kosaraju算法)

- -   - -   - -   - -

一个()打成[]  看了一晚上.....

/*
求强连通分量 kosaraju算法
边表存图 正反构造两个图
跑两边 分别记下入栈顺序 和每个强连通分量的具体信息
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#define maxn 1010
#define maxx 10010
using namespace std;
int n,m,num,head1[maxn],head2[maxn],f[maxn],cnt;
int flag[maxn],ans[maxn][maxn];
stack<int>s;
struct node
{
    int u,v,per;
}e1[maxx],e2[maxx];
void Input()//输入 构图 e1为正 e2为反
{
    int i,x,y;
    cin>>n>>m;
    for(i=1;i<=m;i++)
      {
          cin>>x>>y;
          num++;
          e1[num].u=x;
          e1[num].v=y;
          e1[num].per=head1[x];
          head1[x]=num;
          e2[num].u=y;
          e2[num].v=x;
          e2[num].per=head2[y];
          head2[y]=num;
      }
}
void Dfs1(int k)
{
    f[k]=1;
    for(int p=head1[k];p;p=e1[p].per)
      {
          if(!f[e1[p].v])
            Dfs1(e1[p].v);
      }
    s.push(k);//记录入栈顺序
}
void Dfs2(int k)
{
    f[k]=1;
    ans[cnt][++ans[cnt][0]]=k;//记下第cnt个强连通分量的每个点
    for(int i=head2[k];i;i=e2[i].per)
      if(f[e2[i].v]==0)
        Dfs2(e2[i].v);
    if(ans[cnt][0]>1)flag[k]=1;//如果第 cnt个强连通分量的大小>1 则x属于某个强连通分量
}
void Kosaraju()
{
    memset(f,0,sizeof(f));
    for(int i=1;i<=n;i++)//跑第一遍Dfs 每个点依次入栈
      {
          if(f[i]==0)
            Dfs1(i);
      }
    memset(f,0,sizeof(f));
    while(!s.empty())//跑第二遍Dfs 标记每个点是否属于一个强连通分量 并计算数量
      {
          int tmp=s.top();
          s.pop();
          if(f[tmp]==0)
            {
                cnt++;//计数强连通分量
                Dfs2(tmp);
          }
      }
}
void Printf()
{
    for(int i=1;i<=n;i++)
      if(flag[i]==1)cout<<"T"<<endl;
      else cout<<"F"<<endl;
}
int main()
{
    Input();
    Kosaraju();
    Printf();
    return 0;
}
时间: 2024-10-27 05:11:56

codevs1506传话(kosaraju算法)的相关文章

Kosaraju算法解析: 求解图的强连通分量

1. 定义 连通分量:在无向图中,即为连通子图. 上图中,总共有四个连通分量.顶点A.B.C.D构成了一个连通分量,顶点E构成了一个连通分量,顶点F,G和H,I分别构成了两个连通分量. 强连通分量:有向图中,尽可能多的若干顶点组成的子图中,这些顶点都是相互可到达的,则这些顶点成为一个强连通分量. 上图中有三个强连通分量,分别是a.b.e以及f.g和c.d.h. 2. 连通分量的求解方法 对于一个无向图的连通分量,从连通分量的任意一个顶点开始,进行一次DFS,一定能遍历这个连通分量的所有顶点.所以

Kosaraju 算法检测有向图的强连通性

给定一个有向图 G = (V, E) ,对于任意一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的,则说明该图 G 是强连通的(Strongly Connected).如下图中,任意两个顶点都是互相可达的. 对于无向图,判断图是否是强连通的,可以直接使用深度优先搜索(DFS)或广度优先搜索(BFS),从任意一个顶点出发,如果遍历的结果包含所有的顶点,则说明图是强连通的. 而对于有向图,则不能使用 DFS 或 BFS 进行直接遍历来判断.如下图中,

Kosaraju算法详解

Kosaraju算法可以求出有向图中的强连通分量个数,并且对分属于不同强连通分量的点进行标记.它的算法描述较为简单: (1) 第一次对图G进行DFS遍历,并在遍历过程中,记录每一个点的退出顺序.以下图为例:     如果以1为起点遍历,访问结点的顺序如下: 结点第二次被访问即为退出之时,那么我们可以得到结点的退出顺序: (2)倒转每一条边的方向,构造出一个反图G’.然后按照退出顺序的逆序对反图进行第二次DFS遍历.我们按1.4.2.3.5的逆序第二次DFS遍历: 访问过程如下: 每次遍历得到的那

Kosaraju 算法

Kosaraju 算法 一.算法简介 在计算科学中,Kosaraju的算法(又称为–Sharir Kosaraju算法)是一个线性时间(linear time)算法找到的有向图的强连通分量.它利用了一个事实,逆图(与各边方向相同的图形反转, transpose graph)有相同的强连通分量的原始图. 有关强连通分量的介绍在之前Tarjan 算法中:Tarjan Algorithm 逆图(Tranpose Graph ): 我们对逆图定义如下: GT=(V, ET),ET={(u, v):(v,

Kosaraju 算法查找强连通分支

有向图 G = (V, E) 的一个强连通分支(SCC:Strongly Connected Components)是一个最大的顶点集合 C,C 是 V 的子集,对于 C 中的每一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的. 实际上,强连通分支 SCC 将有向图分割为多个内部强连通的子图.如下图中,整个图不是强连通的,但可以被分割成 3 个强连通分支. 通过 Kosaraju 算法,可以在 O(V+E) 运行时间内找到所有的强连通分支.Ko

CSU 1612: Destroy Tunnels 强连通分量 Kosaraju算法

链接 :  http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1612 题意: 给一个矩阵A 大小N*N, B = A^1 + A^2 + A^3 + .... A^n , B中是否存在非0项. 题目可以转化为 N个点 编号为1-n, 对于任意点v,经过一些任意的步长到达u (u为所有点集的任意一个).离散数学里有图的矩阵相关知识 A^k代表了矩阵中从i到j的步长为k的方法数. 题目就是求整个图是否强连通. 学习了 Kosaraju算法 可以轻

强联通分量之kosaraju算法

首先定义:强联通分量是有向图G=(V, E)的最大结点集合,满足该集合中的任意一对结点v和u,路径vu和uv同时存在. kosaraju算法用来寻找强联通分量.对于图G,它首先随便找个结点dfs,求出每个节点最后一次访问的时间戳f(x),然后我们建立反图Gt,接着根据倒序的时间戳来dfs每个节点,每次dfs到的结点集合就是一个强联通分量.事实上这个算法的思想和拓扑排序类似. 我们来证明它(注意这里面的图指原图,而不是反图): 引理:对于G中的两个强联通分量C和C',若点u属于C,点v属于C',且

[图论] 有向图强连通分量 (kosaraju算法,Tarjan算法)

记录自己的想法:在有向图中,如果一些顶点中任意两个顶点都能互相到达(间接或直接),那么这些顶点就构成了一个强连通分量,如果一个顶点没有出度,即它不能到达其他任何顶点,那么该顶点自己就是一个强连通分量.在用kosaraju算法和Tarjan算法求强连通分量的时候,就是给所有的顶点分组染色,同一种颜色的顶点在同一个强连通分量中,记录有多少种颜色(有多少个强联通分量),每个顶点属于哪种颜色(每个顶点在哪个强连通分量重).在同一个强连通分量中的所有顶点可以缩为一个顶点,然后根据缩点构造DAG(有向无环图

kosaraju算法应用(一)

题目链接:POJ 2186 解题思路: kosaraju算法,本以为要缩点,但是题目只要求找到拓扑排序的一个唯一的头,可以水过--通过计算强连通分量的出度. 代码: #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,m,v[10005],num[1000