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 ...
随机推荐
- Form表单,textarea标签输入框 字数限制,和已输入字数的统计显示
<script type="text/javascript"> $(document).ready(function() { <%-- 页面进来时就调用 --%& ...
- day58 作业
目录 一.做一个图书管理系统页面 二.做一个主页模版 三.点赞 一.做一个图书管理系统页面 <!DOCTYPE html> <html lang="en"> ...
- tinymce 设置和获取编辑器的内容
$('目标元素').html(插入的内容) //设置tinymce编辑器的内容tinymce.get('目标元素').getContent() //获取tinymce编辑器的内容
- C#-CLR note - 26线程
开篇 async/wait的使用 static async Task Main(string[] args) { Console.WriteLine("start-- "); va ...
- Python数据可视化:画饼状图、折线图、圈图
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. from math import pi import matplotlib ...
- LeetCode 84 | 单调栈解决最大矩形问题
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题第52篇文章,我们一起来看LeetCode第84题,Largest Rectangle in Histogram( ...
- 阿里云内部超全K8s实战手册!超全127页可下载
一直关注云计算领域的人,必定知道Docker和Kubernetes的崛起.如今,世界范围内的公有云巨头(谷歌.亚马逊.微软.华为云.阿里云等等)都在其传统的公共云服务之上提供托管的Kubernetes ...
- java基础知识--入门程序说明
①main方法:称为主方法,写法格式固定,是程序的入口或起始点,无论我们编写多少程序,JVM在运行的时候,都会从main方法这里开始执行. ②注释:对代码的解释说明.单行注释//.多行注释/* */. ...
- js JQ动态添加div标签
function renderList(data){ var str = ''; for(var i = 0; i < data.length; i++){ // 动态添加li str += ' ...
- python 批量重命名文件名字
import os print(os.path) img_name = os.listdir('./img') for index, temp_name in enumerate(img_name): ...