前排Orz tarjan

tarjan算法在图的连通性方面有非常多的应用,dfn和low数组真是奥妙重重(并没有很搞懂反正背就完事了)

有向图强连通分量

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<stack>
using namespace std;
struct edge{
int v,next;
}a[];
stack<int>s;
int n,m,u,v,sum=,tt=-,ans=,h[],anss[],num[],nums[],tot=,tim=,dfn[],low[],head[];
bool used[],isin[];
void tarjan(int u){
int v;
used[u]=isin[u]=true;
low[u]=dfn[u]=++tim;
s.push(u);
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
v=a[tmp].v;
if(!used[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else{
if(isin[v])low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
v=-;
sum++;
while(v!=u){
v=s.top();
s.pop();
isin[v]=;
num[v]=sum;
nums[sum]++;
}
}
}
void add(int u,int v){
a[++tot].v=v;
a[tot].next=head[u];
head[u]=tot;
}
int main(){
memset(used,,sizeof(used));
memset(head,-,sizeof(head));
memset(h,-,sizeof(h));
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
scanf("%d%d",&u,&v);
add(u,v);
}
for(int i=;i<=n;i++){
if(!used[i])tarjan(i);
}
tot=;
for(int i=;i<=n;i++){
for(int tmp=head[i];tmp!=-;tmp=a[tmp].next){
if(num[i]!=num[a[tmp].v]){
h[num[i]]=++tot;
}
}
}
for(int i=;i<=sum;i++){
if(nums[i]>)ans++;
}
printf("%d\n",ans);
for(int i=;i<=sum;i++){
if(h[i]==-){
if(tt!=-||nums[i]==){
tt=-;
break;
}else tt=i;
}
}
if(tt==-)printf("-1");
else for(int i=;i<=n;i++){
if(num[i]==tt)printf("%d ",i);
}
return ;
}

无向图割点

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct edge{
int v,next;
}a[];
int t=,n,s,ss,u,v,tim=,sum=,tot=,head[],dfn[],low[];
bool f=false,used[],ff[];
void add(int u,int v){
a[++tot].v=v;
a[tot].next=head[u];
head[u]=tot;
}
void tarjan(int u,int fa){
int v;
dfn[u]=low[u]=++tim;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
v=a[tmp].v;
if(!low[v]){
tarjan(v,u);
if(u==)sum++;
low[u]=min(low[u],low[v]);
if(u!=&&dfn[u]<=low[v]){
ff[u]=true;
}
}else if(v!=fa){
low[u]=min(low[u],dfn[v]);
}
}
}
void dfs(int u){
int v;
used[u]=true;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
v=a[tmp].v;
if(!used[v])dfs(v);
}
}
int main(){
while(scanf("%d",&s)&&s){
printf("Network #%d\n",++t);
memset(head,-,sizeof(head));
memset(ff,,sizeof(ff));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
tot=n=sum=tim=;
f=false;
scanf("%d",&ss);
add(s,ss);
add(ss,s);
n=max(n,max(s,ss));
scanf("%d",&s);
while(s){
scanf("%d",&ss);
add(s,ss);
add(ss,s);
n=max(n,max(s,ss));
scanf("%d",&s);
}
tarjan(,-);
if(sum>)ff[]=true;
for(int i=;i<=n;i++){
if(ff[i]){
memset(used,,sizeof(used));
f=used[i]=true;
sum=;
for(int j=;j<=n;j++){
if(!used[j]){
sum++;
dfs(j);
}
}
printf(" SPF node %d leaves %d subnets\n",i,sum);
}
}
if(!f){
printf(" No SPF nodes\n");
}
printf("\n");
}
return ;
}
/*
1 2
5 4
3 1
3 2
3 4
3 5
0 1 2
2 3
3 4
4 5
5 1
0 1 2
2 3
3 4
4 6
6 3
2 5
5 1
0 0
--------
Network #1
SPF node 3 leaves 2 subnets Network #2
No SPF nodes Network #3
SPF node 2 leaves 2 subnets
SPF node 3 leaves 2 subnets
*/

无向图点双连通分量

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<stack>
using namespace std;
struct edge{
int v,next;
}a[];
struct edge1{
int u,v;
};
int n,m,u,v,tot=,tim=,bcctot=,bccnum[],head[],dfn[],low[],iscut[];
vector<int>ans[];
stack<edge1>s;
void add(int u,int v){
a[++tot].v=v;
a[tot].next=head[u];
head[u]=tot;
}
void tarjan(int u,int fa){
edge1 t;
int v,son;
dfn[u]=low[u]=++tim;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
v=a[tmp].v;
if(v==fa)continue;
t.u=u;
t.v=v;
if(!dfn[v]){
s.push(t);
son++;
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
iscut[u]=true;
ans[++bcctot].clear();
while(true){
edge1 tt=s.top();
s.pop();
if(bccnum[tt.u]!=bcctot){
ans[bcctot].push_back(tt.u);
bccnum[tt.u]=bcctot;
}
if(bccnum[tt.v]!=bcctot){
ans[bcctot].push_back(tt.v);
bccnum[tt.v]=bcctot;
}
if(tt.u==u&&tt.v==v)break;
}
}
}else if(dfn[v]<low[u]){
s.push(t);
low[u]=min(low[u],dfn[v]);
}
}
if(fa<&&son==)iscut[u]=false;
}
int main(){
memset(iscut,,sizeof(iscut));
memset(head,-,sizeof(head));
memset(low,,sizeof(low));
memset(bccnum,,sizeof(bccnum));
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
tarjan(,-);
for(int i=;i<=bcctot;i++){
printf("%d:",i);
for(int j=;j<ans[i].size();j++){
printf("%d ",ans[i][j]);
}
printf("\n");
}
return ;
}
/*
6 7
1 2
2 3
1 3
3 4
4 5
3 5
5 6
--------
1:5 6
2:4 3 5
3:2 1 3
*/

无向图求桥

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct edge{
int u,v,next;
}a[];
int n,m,u,v,tot=,tim=,head[],dfn[],low[],ansu[],ansv[];
void add(int u,int v){
a[++tot].u=u;
a[tot].v=v;
a[tot].next=head[u];
head[u]=tot;
}
void tarjan(int u,int fa){
int v;
dfn[u]=low[u]=++tim;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
v=a[tmp].v;
if(dfn[v]==){
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]){
ansu[++ansu[]]=u;
ansv[++ansv[]]=v;
}
}else{
if(dfn[v]<dfn[u]&&v!=fa){
low[u]=min(low[u],dfn[v]);
}
}
}
}
int main(){
memset(head,-,sizeof(head));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
ansu[]=;
ansv[]=;
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
tarjan(,-);
printf("--------\n");
for(int i=;i<=ansv[];i++){
printf("%d %d\n",ansu[i],ansv[i]);
}
return ;
}
/*
6 7
1 2
2 3
1 3
3 4
4 5
5 6
6 4
--------
3 4
*/

无向图边双连通分量

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
struct edge{
int v,next;
}a[];
int n,m,u,v,tot=,tim=,num=,head[],dfn[],low[],bl[];
bool used[],bri[];
vector<int>g[];
void add(int u,int v){
a[++tot].v=v;
a[tot].next=head[u];
head[u]=tot;
}
void tarjan(int u,int fa){
int v;
dfn[u]=low[u]=++tim;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
v=a[tmp].v;
if(dfn[v]==){
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]){
bri[tmp]=true;
bri[tmp^]=true;
}
}else{
if(dfn[v]<dfn[u]&&v!=fa){
low[u]=min(low[u],dfn[v]);
}
}
}
}
void dfs(int u){
used[u]=true;
bl[u]=num;
g[num].push_back(u);
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(bri[tmp])continue;
if(!used[v])dfs(v);
}
}
int main(){
memset(head,-,sizeof(head));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(used,,sizeof(used));
memset(bri,,sizeof(bri));
memset(bl,,sizeof(bl));
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
for(int i=;i<=n;i++){
if(!dfn[i])tarjan(i,-);
}
for(int i=;i<=n;i++){
if(!used[i]){
num++;
dfs(i);
}
}
for(int i=;i<=num;i++){
printf("%d: ",i);
for(int j=;j<g[i].size();j++)printf("%d ",g[i][j]);
printf("\n");
}
return ;
}

Tarjan专题的更多相关文章

  1. 【noip暑假tarjan专题】

    %%%奎老师 A:傻逼缩点...傻逼编译器卡我next... B:就是这道奎老师没讲清楚的题,明明小朋友们都一A嘛,,,明明细节有很多嘛,,,怎么都这么熟练啊. C:本质还是B,换了个马甲而已. D: ...

  2. 校际联合Contest

    每次开一个坑都像是重新被碾压的预感 最近的新闻,以前很喜欢乔任梁的<复活>...然后他就死了...感觉我再多愁善感一点的话...就要悲伤逆流成河了吧... Contest 09/24(乐滋 ...

  3. 连通图(Tarjan算法) 专题总结

    一.题目类型: 1.有向图的强连通分量: POJ1236 Network of Schools HDU1269 迷宫城堡 2.割点 & 割边: UESTC - 900 方老师炸弹 UVA315 ...

  4. tarjan 题目汇总(含解析)

    下面容许我偷个懒,洛谷上写过的blog我就不来再抄一遍了 洛谷P3436 [[POI2006]PRO-Professor Szu](别称:作死的老教授) 洛谷P4306 [[JSOI2010]连通数] ...

  5. POJ 1470 Closest Common Ancestors (LCA,离线Tarjan算法)

    Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 13372   Accept ...

  6. Tarjan 算法求 LCA / Tarjan 算法求强连通分量

    [时光蒸汽喵带你做专题]最近公共祖先 LCA (Lowest Common Ancestors)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili tarjan LCA - YouTube Tarj ...

  7. NOIp 图论算法专题总结 (2)

    系列索引: NOIp 图论算法专题总结 (1) NOIp 图论算法专题总结 (2) NOIp 图论算法专题总结 (3) 树链剖分 https://oi-wiki.org/graph/heavy-lig ...

  8. 20行代码实现,使用Tarjan算法求解强连通分量

    今天是算法数据结构专题的第36篇文章,我们一起来继续聊聊强连通分量分解的算法. 在上一篇文章当中我们分享了强连通分量分解的一个经典算法Kosaraju算法,它的核心原理是通过将图翻转,以及两次递归来实 ...

  9. DFS序专题

    牛客专题之DFS序 简介 dfs序: 每个节点在dfs深度优先遍历中的进出栈的时间序列,也就是tarjan算法中的dfn数组. 画个图理解一下: 这棵树的dfs序:1 3 2 4 2 5 6 7 6 ...

随机推荐

  1. Core Animation 负责将bitmap绑定提交到 GPU-[CALayer _display]

    Core Animation 负责将bitmap绑定提交到 GPU: Core Animation一头连着CPU,一头连着GPU. ZSTest`-[ZSDTCoreTextCell drawRect ...

  2. CF1038D Slime 构造

    题目大意: 有nnn只史莱姆qwq,每只史莱姆有一个分数,每次一只史莱姆可以吞掉左边的或者右边的史莱姆(要是有的话),然后ta的分数会减去被吞的史莱姆的分数,问最后剩下的史莱姆分数最大为多少 输入格式 ...

  3. 路飞学城Python-Day33

    1.简述计算机操作系统中的“中断”的作用? 为什么有中断? 现代操作系统一般都是采用基于时间片的优先级调度算法,把CPU的时间划分为很细粒度的时间片,一个任务每次只能时间这么多的时间,时间到了就必须交 ...

  4. Pyhton学习——Day30

    # 内核态# 用户态# 操作系统的运行是在BOIS启动盘读取代码,从硬盘读取到内存中,被操作系统的内核中,一直存在在内存中# 计算机系统的三层结构:应用软件-->操作系统-->硬件# 一般 ...

  5. onkeydown、onkeypress、onkeyup、onblur、onchange、oninput、onpropertychange的区别

    onkeydown:按下任何键(字母.数字.系统.tab等)都能触发,且对于字母不区分大小写: onkeypress:按下字母.数字键时触发,且对于字母区分大小写; onkeyup:相应的键和onke ...

  6. [CSS3] Responsive Table -- no more table

    When the screen size is small, we can use "no more table" solution. So instead of render t ...

  7. [Angular] Handle HTTP Errors in Angular with HttpErrorResponse interface

    When communicating with some backend API, data travels over the network using the HTTP protocol. As ...

  8. 2014年辛星解读css第三节

    第二节我们讲述的差点儿全是CSS的选择器,那么以下这一节我们来讲一下CSS的颜色和文本的一些东西,尽管我对调色不大敏感.可是对于颜色还是比較感兴趣的. *********CSS中的颜色******** ...

  9. php给图片加入文字水印

    PHP对图片的操作用到GD库.这里我们介绍怎样给图片加入文字水印. 大致分为四步: 1.打开图片 2.操作图片 3.输出图片 4.销毁图片 以下我们上代码来详细解说每步的实现过程: <? php ...

  10. ZOJ 3689 Digging(贪心+dp)

    Digging Time Limit: 2 Seconds      Memory Limit: 65536 KB When it comes to the Maya Civilization, we ...