这里的Tarjan是基于DFS,用于求有向图的强联通分量。

运用了一个点dfn时间戳和low的关系巧妙地判断出一个强联通分量,从而实现一次DFS即可求出所有的强联通分量。

§有向图中, u可达v不一定意味着v可达u.
   相互可达则属于同一个强连通分量
   (Strongly Connected Component, SCC)
§有向图和它的转置的强连通分量相同
§所有SCC构成一个DAG(有向无环图)

dfn[u]为节点u搜索的次序编号(时间戳),即首次访问u的时间

low[u]为u或u的子树能够追溯到的最早的栈中节点的次序号,即它所在的某个强联通分量(可能是自己一个点,也可能是一棵树)对应的搜索子树的根的访问时间

不难知道,当dfn(u)=low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。

伪代码如下

tarjan(u)
{
DFN[u]=Low[u]=++time // 为节点u设定次序编号和Low初值
Stack.push(u) // 将节点u压入栈中
for each (u, v) in E // 枚举以u为起点的每一条边
if (v is not visted) // 如果节点v未被访问过
tarjan(v) // 继续向下找
Low[u] = min(Low[u], Low[v])
else if (v in S) // 如果节点v还在栈内,则形成一个强联通分量,low值为根的dfn
Low[u] = min(Low[u], DFN[v])//注意到环可能不止一个,有可能是环套环,所以我们的环是要最大的,也就是访问该子树根的时间要尽可能的早
if (DFN[u] == Low[u]) // 如果节点u是强连通分量的根
repeat
v = S.pop // 将v退栈,为该强连通分量中一个顶点
print v
until (u==v)
}

至于缩点,我们可以强行重新建一个图,但有时我们只需要新图的一些性质,所以有时我们可以不需要重新建图,只统计我们需要的数据就可以了。一个例子可以看下面的例题。

POJ2186 Popular Cows

题目描述

每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶

牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜

欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你

算出有多少头奶牛可以当明星。

输入输出格式

输入格式:
第一行:两个用空格分开的整数:N和M

第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B

输出格式:
第一行:单独一个整数,表示明星奶牛的数量

输入输出样例

输入样例#1:
3 3
1 2
2 1
2 3
输出样例#1:
1
说明

只有 3 号奶牛可以做明星

【数据范围】

10%的数据N<=20, M<=50

30%的数据N<=1000,M<=20000

70%的数据N<=5000,M<=50000

100%的数据N<=10000,M<=50000

 牛的相互喜欢构成了一个有向图,题目则要求我们求出一个点,这个点是其他所有点都可以到达的。

对于形成环的点,他们之间能相互到达,所以我们可以把它们缩成一个点。

这样我们通过tarjan缩点之后就形成了一个DAG,分析可以知道一个其他所有点都能到达的点的出度一定为0(因为缩点后不存在环,所以一旦某个点有出度,则出度所指向的点无法再返回到原来的点了),所以如果有一个出度为0的点,这个点所对应的牛的数量就是答案明星奶牛的数量,但是如果有两个以上的出度为0的点,某两个出度为0的点必定无法相互到达,故不存在题目所说的明星奶牛,为0.

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
const int tvt=;
const int tot=;
using namespace std;
int dfn[tvt],low[tvt],zhan[tvt],out[tvt],head[tot],next[tot],to[tot],belong[tvt],total[tvt],inde,n,m,len,ans,num; //out负责统计点的出度,total负责统计某个强联通分量的点的个数,inde就是时间(戳),ans统计出度为的个数
void add(int u,int v){
num++;
next[num]=head[u];
to[num]=v;
head[u]=num;
}
void tarjan(int u){
dfn[u]=low[u]=++inde;
zhan[++len]=u;
for (int i=head[u];i!=;i=next[i]){
int v=to[i];
if (!dfn[v]){
tarjan(v);
low[u]=min(low[v],low[u]);
}
else low[u]=min(low[u],dfn[v]);
}
if (dfn[u]==low[u])
do{int v=zhan[len--];
belong[v]=u;
out[v]=;
total[u]++;
}while(zhan[len+]!=u); //即(v==u)
}
int main(){
scanf("%d%d",&n,&m);
num=;
memset(next,,sizeof(next));
memset(zhan,,sizeof(zhan));
memset(belong,,sizeof(belong));
memset(total,,sizeof(total));
memset(head,,sizeof(head));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(out,,sizeof(out));
memset(to,,sizeof(to));
for (int i=;i<=m;i++){
int x=,y=;
scanf("%d%d",&x,&y);
add(x,y);//添边
}
len=;
for (int i=;i<=n;i++)
belong[i]=i;
inde=;
for (int i=;i<=n;i++)
if (!dfn[i]) tarjan(i);
for (int i=;i<=n;i++)
for (int j=head[i];j!=;j=next[j]){
int v=to[j];
if (belong[i]!=belong[v]) out[belong[i]]++;//缩点,不在同一个强联通分量的话就视为两个点;把在同一个强联通分量的点的出度都统计到一个点上,达到“缩点效果”
}
ans=;
for (int i=;i<=n;i++){
if ((belong[i]==i)&&(!out[i])) ans++;
if (ans>=) break;
}
if (ans==) for (int i=;i<=n;i++) if ((belong[i]==i)&&(!out[i])){
cout<<total[i]<<endl;
return ;
}
else;
else cout<<''<<endl;
return ;
}

神奇的代码

tarjan后,我们只需要点的出度,那么我们进行“缩点”,考察缩点后点的性质,对于在同一个强联通分量的点它们之间连线产生的出度就不计,就只计不在同一个强联通分量的点的出度,并且对同一个强联通分量的所有点的出度都集中到这个分量的某个点上,这样我们就达到了我们需要的效果的“缩点”。belong数组能够告诉我们两个点是不是在同一个强联通分量里

所以,缩点实际上是根据缩点后的我们需要的性质是怎么变化的,我们就针对那个性质去统计。

强连通分量tarjan缩点——POJ2186 Popular Cows的更多相关文章

  1. POJ 1236 Network of Schools(强连通分量/Tarjan缩点)

    传送门 Description A number of schools are connected to a computer network. Agreements have been develo ...

  2. POJ-2186-Popular Cows(强连通分量,缩点)

    链接:https://vjudge.net/problem/POJ-2186 题意: 有N(N<=10000)头牛,每头牛都想成为most poluler的牛,给出M(M<=50000)个 ...

  3. Tarjan求强连通分量,缩点,割点

    Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...

  4. Tarjan算法求有向图强连通分量并缩点

    // Tarjan算法求有向图强连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> #inc ...

  5. 洛谷——P2341 [HAOI2006]受欢迎的牛//POJ2186:Popular Cows

    P2341 [HAOI2006]受欢迎的牛/POJ2186:Popular Cows 题目背景 本题测试数据已修复. 题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所 ...

  6. Instantaneous Transference(强连通分量及其缩点)

    http://poj.org/problem?id=3592 题意:给出一个n*m的矩阵,左上角代表起始点,每个格子都有一定价值的金矿,其中‘#’代表岩石不可达,‘*’代表时空门可以到达指定格子,求出 ...

  7. ZOJ 3795 Grouping 强连通分量-tarjan

    一开始我还天真的一遍DFS求出最长链以为就可以了 不过发现存在有向环,即强连通分量SCC,有向环里的每个点都是可比的,都要分别给个集合才行,最后应该把这些强连通分量缩成一个点,最后保证图里是 有向无环 ...

  8. 强连通分量(tarjan求强连通分量)

    双DFS方法就是正dfs扫一遍,然后将边反向dfs扫一遍.<挑战程序设计>上有说明. 双dfs代码: #include <iostream> #include <cstd ...

  9. POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23445   Accepted: 9605 Des ...

随机推荐

  1. ntopng-一款流量审计框架的安装以及应用

    核心交换机镜像流量审计对于企业应急响应和防患于未然至关重要,本文想通过介绍ntopng抛砖引玉讲一讲流量审计的功能和应用. 安装 安装依赖环境: sudo yum install subversion ...

  2. JavaWeb 环境搭建

    环境搭建 JDK7 Java基本开发工具包 安装(目录[不要使用中文和空格].JDK+JRE) 配置环境变量[JAVA_HOME.path.classpath] 2.        Tomcat7 提 ...

  3. 关于MATLAB处理大数据坐标文件2017529

    今天我们离成功又近了一步,因为又失败了两次 第一次使用了所有特征,理由:前天的特征使用的是取单个特征测试超过85分的特征,结果出现过拟合现象. 本次使用所有特征是为了和昨天的结果作比较. 结果稍好:比 ...

  4. 记一次使用搬瓦工VPS的经历

    自己因为有需求上Google,以前是通过修改hosts的方法实现访问Google,但是最近不知道为什么改hosts后还是无法访问Google,于是决定搭建VPS来实现科学上网,看了一下价格,作为穷逼学 ...

  5. PHP扩展开发-1

    开发环境信息 1.基本环境信息如下: [root@localhost lib]# cat /etc/os-release NAME="CentOS Linux" VERSION=& ...

  6. PHP中小小的header函数

    不废话,直接说功能 1.重定向,语法: header("location:http://www.lemon-x.ga"); file_put_contents("./te ...

  7. 【LeetCode】138. Copy List with Random Pointer

    题目: A linked list is given such that each node contains an additional random pointer which could poi ...

  8. 【LeetCode】94. Binary Tree Inorder Traversal

    题目: Given a binary tree, return the inorder traversal of its nodes' values. For example:Given binary ...

  9. 手机cpu结构,arm

    问题描述 今天测试人员测试集成版本时除了一个bug:关于华为 Mate 8手机Android 6.0系统运行刚刚提测的版本时,出现闪退的bug,而小米 4 手机Android 6.0系统却没有出现任何 ...

  10. 如何使用VBS脚本给在直播间授权登陆

    直接上代码,看不懂说明你技术不够 set WshShell=WScript.CreateObject("WScript.Shell") Dim ie Set mouse=New S ...