强连通分量tarjan缩点——POJ2186 Popular Cows
这里的Tarjan是基于DFS,用于求有向图的强联通分量。
运用了一个点dfn时间戳和low的关系巧妙地判断出一个强联通分量,从而实现一次DFS即可求出所有的强联通分量。
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的更多相关文章
- POJ 1236 Network of Schools(强连通分量/Tarjan缩点)
传送门 Description A number of schools are connected to a computer network. Agreements have been develo ...
- POJ-2186-Popular Cows(强连通分量,缩点)
链接:https://vjudge.net/problem/POJ-2186 题意: 有N(N<=10000)头牛,每头牛都想成为most poluler的牛,给出M(M<=50000)个 ...
- Tarjan求强连通分量,缩点,割点
Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...
- Tarjan算法求有向图强连通分量并缩点
// Tarjan算法求有向图强连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> #inc ...
- 洛谷——P2341 [HAOI2006]受欢迎的牛//POJ2186:Popular Cows
P2341 [HAOI2006]受欢迎的牛/POJ2186:Popular Cows 题目背景 本题测试数据已修复. 题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所 ...
- Instantaneous Transference(强连通分量及其缩点)
http://poj.org/problem?id=3592 题意:给出一个n*m的矩阵,左上角代表起始点,每个格子都有一定价值的金矿,其中‘#’代表岩石不可达,‘*’代表时空门可以到达指定格子,求出 ...
- ZOJ 3795 Grouping 强连通分量-tarjan
一开始我还天真的一遍DFS求出最长链以为就可以了 不过发现存在有向环,即强连通分量SCC,有向环里的每个点都是可比的,都要分别给个集合才行,最后应该把这些强连通分量缩成一个点,最后保证图里是 有向无环 ...
- 强连通分量(tarjan求强连通分量)
双DFS方法就是正dfs扫一遍,然后将边反向dfs扫一遍.<挑战程序设计>上有说明. 双dfs代码: #include <iostream> #include <cstd ...
- POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】
Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 23445 Accepted: 9605 Des ...
随机推荐
- Bash启动选项
Bash选项可以用来控制它的行为,有两种选项:单字符选项和多字符选项,多字符选项必须出现在单字符选项以前.1)单字符选项:由一个减号和一个字符组成2)多字符选项:由两个减号和多个字符组成 常用选项:- ...
- android 下 利用webview实现浏览器功能
android 下 利用webview实现浏览器功能(一): 1.界面添加WEBVIEW控件. 2.在界面.JAVA代码页面(protected void onCreate(Bundle savedI ...
- 页面实现多个定时器(计时器)时选用NSTimer还是GCD?(干货不湿)
定时器在我们每个人做的iOS项目里面必不可少,如登录页面倒计时.支付期限倒计时等等,一般来说使用NSTimer创建定时器: + (NSTimer *)timerWithTimeInterval:(NS ...
- MongoDB--MapReduce分布统计s
MapReduce Mapreduce:要操作的目标集合 Map:映射函数(生成键值对序列,作为reduce函数参数) //传入分组的key和需要统计的值 Reduce:统计函数 //格式化返回的参数 ...
- MongoDB--GridFS 文件存储系统
GridFS是Mongo的一种专门用存储小型文件的功能. 使用于下列场景: 1.写入文件:mongofiles put 文件路径 注意,当前mongo实例链接的哪个库,将写文件在哪个实例里面的grid ...
- CSS3学习系列之盒样式(二)
text-overflow属性 当通过把overflow属性的属性值设定为"hidden"的方法,将盒中容纳不下的内容隐藏起来时,如果使用text-overflow属性,可以在盒的 ...
- Disruptor的应用示例——大文件拆分
结合最近Disruptor的学习,和之前一直思考解决的大文件拆分问题,想到是否可以使用Disruptor作为生产者/消费者传递数据的通道呢?借助其高效的传递,理论上应当可以提升性能.此文便是此想法的落 ...
- 屏幕适配/autoLayout autoresizingMask
#pragma mark-- 屏幕适配/autoLayout autoresizingMask 1> 发展历程 代码计算frame -> autoreszing(父控件和子控件的关系) - ...
- InstallShield -6109
背景:C#项目打包生成时一直提示生成失败,消息号-6109, 查找了好多资料均未能解决,有说ActiveX问题,有说注册表问题,作了相应修改依然未果:后来翻来翻去看到有关User32.dll引用时失败 ...
- nodejs模块学习: connect2解析
nodejs模块学习: connect2 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创造大量的轮子来 ...