强连通分量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 ...
随机推荐
- Idea 常用功能汇总,工作中常用技巧
1.隐藏没用到的文件 比如 IDEA 的项目配置文件(.iml 和.idea),打开 Settings-File Types, 加入要隐藏的文件后缀. 2.常用技巧 2.1 通过Alt+F8查看变量 ...
- 写代码中遇到的问题(php接收不到传过来的json数据,php使用utf8的用法)
今天写代码用python处理完数据,传给php服务器后,发现接收不到数据,因为是跨域,所以加了消息头:header('Access-Control-Allow-Origin:*');但是并没有什么卵用 ...
- ubuntu忽然不能登录,输入密码正确一直返回登录界面
问题描述 由于配置eclipse命令启动,我修改了 /etc/environment 文件的内容,用命令 shutdown -r -now 重启后,输入密码正确一直返回登录界面. 查了下网上资料:系统 ...
- python 打印文件里的内容
>>> import os >>> os.chdir ('e:/')>>> data=open('text.txt')>>> f ...
- 常用JS图片滚动(无缝、平滑、上下左右滚动)代码大全
innerHTML: 设置或获取位于对象起始和结束标签内的 HTML scrollHeight: 获取对象的滚动高度. scrollLeft: 设置或获取位于对象左边界和窗口中目前可见内容的 ...
- SICP-2.2-数据的抽象
数据的抽象 生活中有许多的事物具有复合结构,例如地理位置所用的经纬度,便是通过一个复合结构来代表位置,在我们的程序当中,我们设法将经度纬度组合成一对,我们既可以把他们当做一个整体单元来进行操作,而且也 ...
- 小程序解析html标签wxPrase插件
微信小程序的标签和原来我们习惯用的标签是不一样的,例如视图容器标签小程序是view,然而html就很多比如常用的div就和小程序的view类似. 通常我们在开发小程序(从列表页跳转到详情页)通过富文本 ...
- Spring事务管理注意小事项
在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例外(RunTimeExcep ...
- Java IO学习笔记(四)打印流
1.只有输出流才有打印流:PrintWriter和PrintStream分别针对字符和字节,提供了重载的print,Println方法用于多种数据类型的输出.PrintWriter和PrintStre ...
- [图形学] 习题8.12 NLN二维线段裁剪算法实现
Nicholl-Lee-Nicholl二维线段裁剪算法相对于Cohen-Sutherland和Liang-Barsky算法来说,在求交点之前进行了线段端点相对于几个区域的判断,可以确切的知道要求交点的 ...