Tarjan 做题总结
这两天Tarjan复习完后把题做了做。洛谷题单《图的连通性》已经做得差不多了。大部分是Tarjan的题,所以写一篇小总结。
T1 【模板】 缩点
不多bb。我已经写过关于Tarjan模板的随笔了。传送门
T2 【模板】割点
不多bb。传送门
T3 [USACO03FALL][HAOI2006]受欢迎的牛 G
题意简述:找到出度为0的点/强连通分量,并输出大小。
-----------------------------------------------------------------------------------
先缩点。值得注意的是图中只能有一个出度为0的点。如果有更多的出度为0的点那这些出度为0的点无法互相到达,那么数量就会为0。
数量在弹栈的时候记录就好。
代码:
#include<bits/stdc++.h>
using namespace std;
int head[],shabi;
int st[],top;
int vis[],dfn[],low[],all[],color[],du[];
int n,m,cnt,tot,x,y,k;
struct node
{
int next,to;
}edge[];
void add(int from,int to)
{
edge[++shabi].next=head[from];
edge[shabi].to=to;
head[from]=shabi;
}
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){
if (ch=='-') f=-;
ch=getchar();
}while(''<=ch&&ch<=''){
x=x*+ch-'';
ch=getchar();
}
return x*f;
}
void tarjan(int now)
{
low[now]=dfn[now]=++cnt;
vis[now]=;
st[++top]=now;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
}
if (dfn[now]==low[now]){
tot++;
do{
k=st[top];top--;
color[k]=tot;
vis[k]=;
all[tot]++;
}while(k!=now);
}
}
int main()
{
n=read(),m=read();
for (int i=;i<=m;i++)
{
x=read(),y=read();
add(x,y);
}
for (int i=;i<=n;i++) if(!dfn[i]) tarjan(i);
for (int w=;w<=n;w++)
for (int i=head[w];i;i=edge[i].next)
{
int to=edge[i].to;
if (color[w]!=color[to]) du[color[w]]++;
}
int flag=;
for (int i=;i<=tot;i++)
{
if (!du[i]){
if (flag){
cout<<;
return ;
}
flag=i;
}
}
cout<<all[flag];
return ;
}
Tarjan裸题。只要把强连通分量的大小记录下来,如果$num[i]\geq 2$那么$ans++$。输出$ans$即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=;
const int maxm=;
int dfn[maxn],low[maxn],vis[maxn],num[maxn],pos[maxn],cnt,tot;
int st[maxn],top;
int head[maxm],jishu;
int n,m,ans;
struct node
{
int next,to;
}edge[maxm];
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if (ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void add(int from,int to)
{
edge[++jishu].next=head[from];
edge[jishu].to=to;
head[from]=jishu;
}
void tarjan(int now)
{
vis[now]=;
st[++top]=now;
dfn[now]=low[now]=++cnt;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
}
if (dfn[now]==low[now])
{
tot++;
while(st[top+]!=now)
{
pos[st[top]]=tot;
num[tot]++;
vis[st[top--]]=;
}
}
}
int main()
{
n=read(),m=read();
for (int i=;i<=m;i++)
{
int u=read(),v=read();
add(u,v);
}
for (int i=;i<=n;i++) if (!dfn[i]) tarjan(i);
for (int i=;i<=tot;i++) if (num[i]>) ans++;
printf("%d",ans);
return ;
}
T5 [USACO5.3]校园网Network of Schools
子问题1就是求缩点后入度为零的点的数量。子问题2就是求$max(ans1,ans2)$。
仔细读读题还是能明白要干什么的。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=;
const int maxm=;
int dfn[maxn],low[maxn],vis[maxn],pos[maxn],cnt,tot;
int st[maxn],top;
int head[maxm],jishu;
int n,fat[maxn][],k,in[maxn],out[maxn];
struct node
{
int next,to;
}edge[maxm];
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if (ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void add(int from,int to)
{
edge[++jishu].next=head[from];
edge[jishu].to=to;
head[from]=jishu;
}
void tarjan(int now)
{
vis[now]=;st[++top]=now;
dfn[now]=low[now]=++cnt;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
}
if (dfn[now]==low[now])
{
tot++;
while(st[top+]!=now)
{
pos[st[top]]=tot;
vis[st[top--]]=;
}
}
}
int main()
{
n=read();
for (int i=;i<=n;i++)
{
int x=read();
while(x!=)
{
add(i,x);
fat[++k][]=i;
fat[k][]=x;
x=read();
}
}
for (int i=;i<=n;i++) if (!dfn[i]) tarjan(i);
for (int i=;i<=k;i++)
if (pos[fat[i][]]!=pos[fat[i][]]) in[pos[fat[i][]]]++,out[pos[fat[i][]]]++;
int ans1=,ans2=;
for (int i=;i<=tot;i++)
{
if (in[i]==) ans1++;
if (out[i]==) ans2++;
}
if (tot==) cout<<<<endl<<;
else cout<<ans1<<endl<<max(ans1,ans2);
return ;
}
T6 上白泽慧音
在弹栈的时候记录强连通分量的大小和字典序就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+;
const int inf=0x3f3f3f3f;
struct note{
int to,nex;
}e[maxn*];
int col,num,head[maxn],dfn[maxn],low[maxn],de[maxn],co[maxn],si[maxn],stk[maxn];
int top,n,m;
int cnt=-;
void add(int x,int y)
{
static int cnt=;
cnt++;
e[cnt].to=y;
e[cnt].nex=head[x];
head[x]=cnt;
} void tarjan(int u)
{
dfn[u]=low[u]=++num;
stk[++top]=u;
for(int i=head[u];i;i=e[i].nex)
{
int v=e[i].to;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!co[v])low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
co[u]=++col;
++si[col];
while(stk[top]!=u)
{
++si[col];
co[stk[top]]=col;
--top;
}
--top;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
int x,y,f;
cin>>x>>y>>f;
if(f==)add(x,y);
if(f==)add(x,y),add(y,x);
}
for(int i=;i<=n;i++)if(!dfn[i])tarjan(i);
for(int i=;i<=col;i++)cnt=max(cnt,si[i]);
cout<<cnt<<endl;
for(int i=;i<=n;i++)
{
if(si[co[i]]==cnt)
{
int now=co[i];
for(int j=i;j<=n;j++)if(co[j]==now)cout<<j<<" ";
return ;
}
}
return ;
}
后记:裸的Tarjan题还是很好看出解法的,但是和其他图论算法结合起来就十分难受了,有时候真的是绞尽脑汁也想不出来。
Tarjan 做题总结的更多相关文章
- UOJ 做题记录
UOJ 做题记录 其实我这么弱> >根本不会做题呢> > #21. [UR #1]缩进优化 其实想想还是一道非常丝播的题目呢> > 直接对于每个缩进长度统计一遍就好 ...
- C语言程序设计做题笔记之C语言基础知识(下)
C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...
- C语言程序设计做题笔记之C语言基础知识(上)
C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎 ...
- 屏蔽Codeforces做题时的Problem tags提示
当在Codeforces上做题的时,有时会无意撇到右侧的Problem tags边栏,但是原本并不希望能够看到它. 能否把它屏蔽了呢?答案是显然的,我们只需要加一段很短的CSS即可. span.tag ...
- ACM 做题过程中的一些小技巧。
ACM做题过程中的一些小技巧. 1.一般用C语言节约空间,要用C++库函数或STL时才用C++; cout.cin和printf.scanf最好不要混用. 2.有时候int型不够用,可以用long l ...
- [日记&做题记录]-Noip2016提高组复赛 倒数十天
写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...
- CodeM美团点评编程大赛复赛 做题感悟&题解
[T1] [简要题意] 长度为N的括号序列,随机确定括号的方向:对于一个已确定的序列,每次消除相邻的左右括号(右左不行),消除后可以进一步合并和消除直到不能消为止.求剩下的括号的期望.\(N \l ...
- (luogu1704)寻找最优美做题曲线 [TPLY]
寻找最优美做题曲线 题目链接:https://www.luogu.org/problemnew/show/P1704 题目大意: 求包含指定点的最长不降子序列(严格递增) 题解 首先我们发现 一个序列 ...
- project euler做题记录
ProjectEuler_做题记录 简单记录一下. problem 441 The inverse summation of coprime couples 神仙题.考虑答案为: \[\begin{a ...
随机推荐
- day58 作业
目录 一.做一个图书管理系统页面 二.做一个主页模版 三.点赞 一.做一个图书管理系统页面 <!DOCTYPE html> <html lang="en"> ...
- PE解析器与加载器编写指南
PE解析器与加载器编写指南 最近准备去实习,看公司要求应该开发PE相关的查杀引擎,因此再回头复习一下PE格式,重新写一个PE解析器和PE加载器,再此记录下有关坑. PE解析器部分: 1)如何确定节区表 ...
- 利用docker部署oxidized网络设备备份系统
随着网络设备的增多,通过人手备份网络设备倍感压力,而且效率低.有编程基础的人可能会通过Python的parimiko 或者netmiko 连接到设备操作 把文件通过ftp 上传到FTP服务器, 在通过 ...
- 阿里云OSS 服务端签名后直传之分片上传(结合element-ui的upload组件)
分片上传(结合element-ui的upload组件实现自定义上传) async uploadFree(content){ let data = await this.getOssToken(); / ...
- 数据结构之二叉搜索树(BST)--JavaScript实现
原理: 叉排序树的查找过程和次优二叉树类似,通常采取二叉链表作为二叉排序树的存储结构.中序遍历二叉排序树可得到一个关键字的有序序列,一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程 ...
- .NET Core CLI 的性能诊断工具介绍
前言 开发人员的.NET Core项目上线后,经常会出现各种问题,内存泄漏,CPU 100%,处理时间长等, 这个时候就需要快速并准确的发现问题,并解决问题, 除了项目本身的日志记录外,NET Cor ...
- 03-Python控制语句
一.简介 通过一些语句来改变程序的执行顺序,这些语句被叫做控制语句,在python主要有if.for.while三种控制流语句. 二.if语句 用来检测一个条件是否成立,如果为真,则执行该语句(一般为 ...
- Crawlab Lite 正式发布,更轻量的爬虫管理平台
Crawlab 是一款基于 Golang 的分布式爬虫管理平台,产品发布已经一年有余,经过开发团队的不断打磨,即将迭代到 v0.5 版本.在这期间我们为 Crawlab 加入了大量社区用户共同期望的功 ...
- C#数据结构与算法系列(二十二):快速排序算法(QuickSort)
1.介绍 快速排序(QuickSort)是对冒泡排序的一种改进,基本思想是:通过一趟排序将要排序的数据分割成独立的两部分, 其中一部分的所有数据都比另一部分的所有数据都要小,然后再按此方法对这两部分数 ...
- Kubernetes的10个基本事实!你知道几个?k8s与Docker又有何不同?
无论您是Kubernetes的新手还是只是想获得更多知识,这篇文章都会帮到您! Kubernetes是一个增长的趋势.近年来,K8s技术经历了从小型开源Google项目到Cloud Native Co ...