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 ...
随机推荐
- day05 垃圾回收机制(超小白讲解)
垃圾回收机制 在学习这个抽象概念前,老习惯,灵魂二问 什么是?为什么要有? 引言:在程序运行到变量定义时,会在内存空间中存放变量值,然而内存空间是有限的,变量是无限的. Q:如何在有限的内存里存里存放 ...
- day03 编程语言介绍
一.编程语言分类 目录 一.编程语言分类 1.低级语言 1.1机器语言 1.2.汇编语言 2.高级语言 2.1编译型语言(例:c语言) 2.2解释型语言(例:世界上最好的语言python) 3总结 二 ...
- CSS的引入与选择器
CSS的引入与选择器 CSS与HTML的关系 Cascading Style Sheet 即层叠样式表 在上一篇文中,已经介绍了一些非常常用的HTML标签,接下来将步入CSS的学习,如果将单纯HTML ...
- 记Centos7和RHEL连接不上网络
一 .前言 我是把Linux系统安装在虚拟机中的,用的是VMware. 在终端工具和操作界面中. VMware里面采用的网络适配器是NAT技术. 标题中的Centos和RHEL区别就不多说了,自行百度 ...
- Java多线程详解总结
一.基本概念 程序(program): 是为完成特定任务.用某种语言编写的一组指令的集合.即指一 段静态的代码,静态对象. 进程(process):是程序的一次执行过程,或是正在运行的一个程序.是一个 ...
- linux目录结构 主流Linux发行版的目录结构
目录 目录结构 一般教学的目录 CentOS7 openSUSE15.1 Ubuntu18.04 详细说明: /dev目录 /etc目录 /proc目录 /usr目录 /var目录 比较重要的目录 文 ...
- Python Ethical Hacking - ARPSpoof_Detector
ARPSPOOF_DETECTOR Watch value for gateway mac in the arp table Nice and simple, but will not detect ...
- bootstrap样式:.clearfix
我们知道,在静态页面的编写中,清除浮动是一件很繁琐的事情. 所以一般的CSS框架都会有用来清除浮动的样式. 在bootstrap中,这个样式叫 clearfix. 只要在需要清除浮动的元素的父元素加上 ...
- Angular 的前世今生
目录 序言 AngularJS 简介 Angular 2.0 的动机 现如今的 Angular Angular 的核心概念 参考 序言 Angular 一般意义上是指 Angular v2 及以上版本 ...
- 【JVM之内存与垃圾回收篇】运行时数据区概述及线程
运行时数据区概述及线程 前言 本节主要讲的是运行时数据区,也就是下图这部分,它是在类加载完成后的阶段 当我们通过前面的:类的加载-> 验证 -> 准备 -> 解析 -> 初始化 ...