图论——强连通分量:Tarjan算法——练习1

简介: 上一次我们详细介绍了强连通分量的Tarjan算法,今天呢,我们来做一些习题来巩固Tarjan算法,毕竟它十分重要。Tarjan算法详解上面是上一次的详解,在做题时可供参考。~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                              练习一般采用洛谷题库。

上一次我们详细介绍了强连通分量的Tarjan算法,今天呢,我们来做一些习题来巩固Tarjan算法,毕竟它十分重要。

Tarjan算法详解

上面是上一次的详解,在做题时可供参考。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                              练习一般采用洛谷题库。  

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

T1.  luogu   P2341   受欢迎的牛    来源: HAOI2006

题目描述

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

牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果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

 

分析

对于奶牛之间的关系,不难看出,可以用一个有向图表示。奶牛A喜欢奶牛B,则转化为节点A到节点B有一条有向边。

然后,我们再来分析一下样例,并从中找到解题方法,解题思路。

 

这,是我们将奶牛之间的关系转化而来的有向图。

不难发现,节点1与节点2形成了强连通分量。我们一看到强连通分量,就要先想到缩点,把问题简单化,不行再想别的方法。

 

这是缩点之后的样子。变成了一个非常简单的图。

那么,接下来怎么办呢?

样例是说只有3号奶牛是“明星”,我们就来看3号奶牛有什么特点。

 

当我们缩完点之后,这个有向无环图(DAG)中,不会再有强连通的两点,于是可以得出两点之间最多只有一条有向路径,也就是不存在两只牛互相喜欢。(我们把构成强连通分量的点看做是一只牛)。

 

这说明什么呢?

 

这说明若一直奶牛是明星,那在缩点之后,它一定不会喜欢任意一头奶牛。这在有向图中叫出度为0。也就是说它没有去别的节点的路径。

如果缩点之后一个由强连通分量组成的节点时明星,则属于这个强连通分量的所有节点都是明星。(他们互相喜欢)。

 

这样一看,题目就变得简单了。

 

解题过程也很明了:

 

1.通过奶牛的关系建立一个有向图。

2.使用Tarjan算法把强连通分量缩成一个点。

3.遍历缩点后的有向图,找出出度为0的节点,加到Ans中去。

4.得解。

 

分析了这么多,大概可以AK了吧。

 

这题思路没有问题,但在一些细节上需要注意,不要掉坑。

接下来开始填坑。

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

数据范围:10000点,于是int的二维数组开不下10000^2,所以存图时建议使用vector(不定长数组)或 链式前向星 来存图。

vector存图:大佬的博客

链式前向星存图:大佬的博客

以上两个博客介绍了这两种优秀的存图方法,不会的可以看一看。

2.有一个大佬说:我们只关注一个分量的出度是否为0,所以不用判断两个分量间的边是否重复统计

3.另一个大佬说:数据水

好吧,也就这些了,最后给代码:

code:

 1 #include<bits/stdc++.h>
 2 #define maxn 1000000
 3 using namespace std;
 4 int Next[maxn],a=0,F[maxn],Head[maxn],cmpi[maxn],out[maxn],E[maxn],cmp[maxn],s[maxn],dfn[maxn],low[maxn],top=0,cmpid=0,tim=0;
 5 bool V[maxn],D[maxn];
 6 void ins(int x,int y,int i)
 7 {
 8     E[i]=y;
 9     Next[i]=Head[x];
10     Head[x]=i;
11 }//链式前向星写法,详见博客
12 int find()
13 {
14     int ans=0;
15     for(int i=1;i<=a;i++)
16     {
17         for(int p=Head[F[i]];p;p=Next[p])//列举这个点的所有邻接点
18         {
19             if(!D[E[p]])ans++;//如果这个点的邻接点不和他在一个强联通分量的话,那么我们就发现他所在的分量有了出度
20         }
21     }
22     return ans;
23 }//找一组强连通分量的出度,若为0,下面的答案就累加
24 void tarjan(int u)
25 {
26     dfn[u]=low[u]=++tim;
27     s[++top]=u;
28     V[u]=true;
29     for(int p=Head[u];p;p=Next[p])
30     {
31         int y=E[p];
32         if(!dfn[y])
33         {
34             tarjan(y);
35             low[u]=min(low[y],low[u]);
36         }
37         else
38         {
39             if(V[y])low[u]=min(low[u],dfn[y]);
40         }
41     }
42     if(dfn[u]==low[u])
43     {
44         int y;
45         cmpid++;
46         do
47         {
48             y=s[top--];
49             V[y]=false;
50             F[++a]=y;//将这个点存入暂时数组
51             D[y]=true;
52             cmpi[cmpid]++;
53         }while(y!=u);
54         cmp[cmpid]=find();//cmp存储他的出度
55         a=0;
56         memset(D,false,sizeof(D));//D数组表示这个点在不在这个强连通分量
57     }
58 }//Tarjan算法缩点,模板在我的博客里有
59 int main()
60 {
61     int n,m;
62     scanf("%d%d",&n,&m);
63     for(int i=1;i<=m;i++)
64     {
65         int a,b;
66         scanf("%d%d",&a,&b);
67         ins(a,b,i);//建图
68     }
69     for(int i=1;i<=n;i++)
70        if(!dfn[i])tarjan(i);
71     int c=0,ans;
72     for(int i=1;i<=cmpid;i++)
73       if(!cmp[i])c++,ans=i;//检查图是否连通
74     if(c==1)
75         printf("%d",cmpi[ans]);
76     else 
77         printf("0");
78     return 0;
79 }         

希望大家在不抄题解的情况下能写对代码,多理解,多总结,这对你们帮助很大。

 

好了,今天的讲解就到这里,之后还会有习题分享给大家,我们下次见。

 

相关文章
|
9月前
|
机器学习/深度学习 安全 算法
【图论】【割点】【C++算法】928. 尽量减少恶意软件的传播 II
【图论】【割点】【C++算法】928. 尽量减少恶意软件的传播 II
|
3月前
|
JSON 算法 数据挖掘
基于图论算法有向图PageRank与无向图Louvain算法构建指令的方式方法 用于支撑qwen agent中的统计相关组件
利用图序列进行数据解读,主要包括节点序列分析、边序列分析以及结合节点和边序列的综合分析。节点序列分析涉及节点度分析(如入度、出度、度中心性)、节点属性分析(如品牌、价格等属性的分布与聚类)、节点标签分析(如不同标签的分布及标签间的关联)。边序列分析则关注边的权重分析(如关联强度)、边的类型分析(如管理、协作等关系)及路径分析(如最短路径计算)。结合节点和边序列的分析,如子图挖掘和图的动态分析,可以帮助深入理解图的结构和功能。例如,通过子图挖掘可以发现具有特定结构的子图,而图的动态分析则能揭示图随时间的变化趋势。这些分析方法结合使用,能够从多个角度全面解读图谱数据,为决策提供有力支持。
145 0
|
9月前
|
算法 Python
Python中实现图论算法
Python中实现图论算法 “【5月更文挑战第20天】”
66 3
|
8月前
|
算法 数据挖掘 定位技术
算法必备数学基础:图论方法由浅入深实践与应用
算法必备数学基础:图论方法由浅入深实践与应用
|
9月前
|
人工智能 算法 BI
【图论】【 割边】【C++算法】1192. 查找集群内的关键连接
【图论】【 割边】【C++算法】1192. 查找集群内的关键连接
|
9月前
|
机器学习/深度学习 算法 测试技术
【深度优先】【图论】【C++算法】2045. 到达目的地的第二短时间
【深度优先】【图论】【C++算法】2045. 到达目的地的第二短时间
|
9月前
|
安全 算法 测试技术
【图论】【并集查找】【C++算法】928. 尽量减少恶意软件的传播 II
【图论】【并集查找】【C++算法】928. 尽量减少恶意软件的传播 II
|
2天前
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
1月前
|
算法 数据安全/隐私保护 计算机视觉
基于Retinex算法的图像去雾matlab仿真
本项目展示了基于Retinex算法的图像去雾技术。完整程序运行效果无水印,使用Matlab2022a开发。核心代码包含详细中文注释和操作步骤视频。Retinex理论由Edwin Land提出,旨在分离图像的光照和反射分量,增强图像对比度、颜色和细节,尤其在雾天条件下表现优异,有效解决图像去雾问题。
|
1月前
|
算法 数据可视化 安全
基于DWA优化算法的机器人路径规划matlab仿真
本项目基于DWA优化算法实现机器人路径规划的MATLAB仿真,适用于动态环境下的自主导航。使用MATLAB2022A版本运行,展示路径规划和预测结果。核心代码通过散点图和轨迹图可视化路径点及预测路径。DWA算法通过定义速度空间、采样候选动作并评估其优劣(目标方向性、障碍物距离、速度一致性),实时调整机器人运动参数,确保安全避障并接近目标。
147 68