这两天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 ;
}

T4 [USACO06JAN]The Cow Prom S

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 做题总结的更多相关文章

  1. UOJ 做题记录

    UOJ 做题记录 其实我这么弱> >根本不会做题呢> > #21. [UR #1]缩进优化 其实想想还是一道非常丝播的题目呢> > 直接对于每个缩进长度统计一遍就好 ...

  2. C语言程序设计做题笔记之C语言基础知识(下)

    C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...

  3. C语言程序设计做题笔记之C语言基础知识(上)

    C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎 ...

  4. 屏蔽Codeforces做题时的Problem tags提示

    当在Codeforces上做题的时,有时会无意撇到右侧的Problem tags边栏,但是原本并不希望能够看到它. 能否把它屏蔽了呢?答案是显然的,我们只需要加一段很短的CSS即可. span.tag ...

  5. ACM 做题过程中的一些小技巧。

    ACM做题过程中的一些小技巧. 1.一般用C语言节约空间,要用C++库函数或STL时才用C++; cout.cin和printf.scanf最好不要混用. 2.有时候int型不够用,可以用long l ...

  6. [日记&做题记录]-Noip2016提高组复赛 倒数十天

    写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...

  7. CodeM美团点评编程大赛复赛 做题感悟&题解

    [T1] [简要题意]   长度为N的括号序列,随机确定括号的方向:对于一个已确定的序列,每次消除相邻的左右括号(右左不行),消除后可以进一步合并和消除直到不能消为止.求剩下的括号的期望.\(N \l ...

  8. (luogu1704)寻找最优美做题曲线 [TPLY]

    寻找最优美做题曲线 题目链接:https://www.luogu.org/problemnew/show/P1704 题目大意: 求包含指定点的最长不降子序列(严格递增) 题解 首先我们发现 一个序列 ...

  9. project euler做题记录

    ProjectEuler_做题记录 简单记录一下. problem 441 The inverse summation of coprime couples 神仙题.考虑答案为: \[\begin{a ...

随机推荐

  1. 使用CodeMirror插件遇到的问题

    CodeMirror的正常使用: //首先通过<script>标签引入相应的js,这个就不必说了 var myCodeMirror = CodeMirror.fromTextArea(my ...

  2. python三器一闭

    前言:python三器一闭i 包含 迭代器.生成器.装饰器,闭包 迭代器 概念:迭代器是一种可以记录可迭代对象遍历的位置,迭代器从第一个元素开始访问,直到访问所有元素访问结束,迭代器只会往前,不会后退 ...

  3. requests接口自动化8-传递数据为xml形式的post请求:data

    传递数据为xml形式的post请求 请求体内容: <?xml version=“1.0” encoding = “UTF-8”?> <COM> <REQ name=&qu ...

  4. python eval函数,将列表样式的字符串转化为列表

    python eval函数,将列表样式的字符串转化为列表 >>> str_1 = '[1,2,3,4,5,6]'>>> type(str_1)<type 's ...

  5. python 并发专题(五):离散事件仿真(事件循环生成器)

    出租车队运营仿真 创建几辆出租车,每辆车会拉几个乘客,然后回家.出租车首先驶离车库,四处徘徊,寻找乘客:拉到乘客后,行程开始:乘客下车后,继续四处徘徊. 程序解释 程序的输出示例: 创建 3 辆出租车 ...

  6. How to use the function of bind

    The usage of  bind  is to define a specified scope for called function. Because the key this is easy ...

  7. Unity-Editor

    Undo.RecordObject [MenuItem("Example/Random Rotate")] static void RandomRotate() { var tra ...

  8. Ethical Hacking - GAINING ACCESS(19)

    Client-Side Attacks - Social Engineering Tool: The FAT RAT Just like Veil, it generates Undetectable ...

  9. vue.js全局组件和局部组件区别

    在id=‘#app’,加入<pl>标签,但也访问不了局部chil组件: 在id=‘#div0’,加入<as>标签,但能访问到全局组件

  10. MySQL Front远程连接数据库

    连接前需要先配置一下服务器端的数据库 进入mysql数据库,选择mysql mysql> use mysql; 选择 host 表 mysql> select host from user ...