Tarjan模板——求强连通分量
Tarjan求强连通分量的流程在这个博客讲的很清楚,再加上我也没理解透,这里就不写了。
缩点:将同一个连通块内的点视为同一个点。
扔一道模板题:codeVS2822爱在心中
第一问很显然就是求点数大于一的连通块的个数,跑一次tarjan;
第二问脑补一下发现,缩点后,若图中有且仅有一个点出度为0且为爱心天使,则该点为所求的特殊爱心天使;
因为当缩点之后,图中不存在环,若有且仅有一个爱心天使出度为0,那么其他点一定有通向该爱心天使的路径。
若有两个点出度为0,那么他们彼此不被对方所爱。
若没有点出度为0,则图中存在环,矛盾。
看起来似乎没什么问题,但是写出来第五个点挂掉了,代码查不出错,若有人看到这篇博客,希望在下方指出错误,谢谢。
#include<cstdio>
#include<stack>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std; struct edge{
int to,next;
}; int a[][],dfn[],low[],head[],i,j,n,m,x,y,tag,ans[];
int ans1=,head2[],out[];
bool visited[],b[],lowb[];
edge e[],e2[];
stack<int> s; void tarjan(int k){
int i,v;
dfn[k]=low[k]=++tag;
b[k]=true;
s.push(k);
for(i=head[k];i!=-;i=e[i].next){
v=e[i].to;
if(!dfn[v]){
tarjan(v);
low[k]=min(low[k],low[v]);
}else
if(b[v])
low[k]=min(low[k],dfn[v]);
}
int tmp=;
if(dfn[k]==low[k]){
//++ans1;
do{
v=s.top();
s.pop();
b[v]=false;
tmp++;
}while(v!=k);
if(tmp>=)++ans1;
}
} int ne=;
void add(int a,int b){
e[++ne].to=b; e[ne].next=head[a]; head[a]=ne;
} void add2(int a,int b){
e2[++ne].to=b; e2[ne].next=head2[a]; head2[a]=ne;
} int main(){
memset(head,-,sizeof(head));
memset(head2,-,sizeof(head2));
scanf("%d%d",&n,&m);
for(i=;i<=m;i++){
scanf("%d%d",&x,&y);
add(x,y);
}
tag=;
memset(dfn,,sizeof(dfn));
for(i=;i<=n;i++){
if(!dfn[i])tarjan(i);
}
printf("%d\n",ans1); ne=;
int n2=; for(i=;i<=n;i++){
if(!lowb[low[i]]){
n2=max(n2,low[i]);
lowb[low[i]]=true;//记录缩点后图中节点的编号
}
a[low[i]][++a[low[i]][]]=i;
for(j=head[i];j!=-;j=e[j].next){
int v=e[j].to;
if(low[i]!=low[v])
add2(low[i],low[v]);
}
//缩点:将low[]值相等的点看做一个点
} for(i=;i<=n2;i++){
if(!lowb[i])continue;
for(j=head2[i];j!=-;j=e2[j].next)
out[i]++;
} int sum=;
for(i=;i<=n2;i++){
if(out[i]==&&lowb[i]){
sum++;
j=i;
};
} if(sum!=||a[j][]<=){
printf("%d\n",-);
return ;
} for(i=;i<=a[j][];i++)
ans[i]=a[j][i]; sort(ans+,ans++a[j][]); for(i=;i<=a[j][];i++)
printf("%d ",ans[i]); printf("\n");
return ;
}
16.11.18:换了一种写法A了,然而还是不知道原来的代码有什么问题;
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;
struct edge{int to,next;}e1[],e2[];
int head1[],head2[],dfn[],low[],belong[],out[];
bool instack[];
stack<int> s;
int dep,ne1,ne2,ans1,n,m,co;
void add1(int a,int b){
e1[++ne1].to=b;e1[ne1].next=head1[a];head1[a]=ne1;
}
void add2(int a,int b){
e2[++ne2].to=b;e2[ne2].next=head2[a];head2[a]=ne2;
}
void tarjan(int k){
dfn[k]=low[k]=++dep;
instack[k]=true;
s.push(k);
for(int i=head1[k];i!=-;i=e1[i].next){
int v=e1[i].to;
if(!dfn[v]){
tarjan(v);
low[k]=min(low[k],low[v]);
}
else if(instack[v])
low[k]=min(low[k],dfn[v]);
}
int t;
if(low[k]==dfn[k]){
int tmp=;
++co;
do{
t=s.top();
s.pop();
instack[t]=false;
belong[t]=co;//染色缩点
tmp++;
}while(t!=k);
if(tmp>)++ans1;
}
} int main(){
memset(head1,-,sizeof(head1));
memset(head2,-,sizeof(head2));
int i,j,u,v;
scanf("%d%d",&n,&m);
for(i=;i<=m;i++){
scanf("%d%d",&u,&v);
add1(u,v);
}
for(i=;i<=n;i++){
if(!dfn[i])tarjan(i);
}
printf("%d\n",ans1); int sum=,ang=;
for(i=;i<=n;i++){
for(j=head1[i];j!=-;j=e1[j].next){
int v=e1[j].to;
if(belong[v]!=belong[i]){
out[belong[i]]++;//若邻接的两点颜色不同,则出度加一。
}
}
}
for(i=;i<=co;i++){
if(out[i]==){
ang=i;
++sum;
}
}
if(sum==){
int sum2=;
for(i=;i<=n;i++){
if(belong[i]==ang)sum2++;
}
if(sum2>){
for(i=;i<=n;i++){
if(belong[i]==ang)printf("%d ",i);
}
printf("\n");
}else{printf("-1\n");return ;}
return ;
}
printf("-1\n");return ;
}
Tarjan模板——求强连通分量的更多相关文章
- Tarjan 算法求 LCA / Tarjan 算法求强连通分量
[时光蒸汽喵带你做专题]最近公共祖先 LCA (Lowest Common Ancestors)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili tarjan LCA - YouTube Tarj ...
- HDU 1269 迷宫城堡 tarjan算法求强连通分量
基础模板题,应用tarjan算法求有向图的强连通分量,tarjan在此处的实现方法为:使用栈储存已经访问过的点,当访问的点离开dfs的时候,判断这个点的low值是否等于它的出生日期dfn值,如果相等, ...
- [学习笔记] Tarjan算法求强连通分量
今天,我们要探讨的就是--Tarjan算法. Tarjan算法的主要作用便是求一张无向图中的强连通分量,并且用它缩点,把原本一个杂乱无章的有向图转化为一张DAG(有向无环图),以便解决之后的问题. 首 ...
- 【算法】Tarjan算法求强连通分量
概念: 在有向图G中,如果两个定点u可以到达v,并且v也可以到达u,那么我们称这两个定点强连通. 如果有向图G的任意两个顶点都是强连通的,那么我们称G是一个强连通图. 一个有向图中的最大强连通子图,称 ...
- tarjan算法求强连通分量
先上代码: #include <iostream> #include <cstring> #include <vector> #include <stack& ...
- HDU1269迷宫城堡(裸Tarjan有向图求强连通分量个数)
迷宫城堡Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...
- tarjan 算法求强连通分量
#include<bits/stdc++.h> #define ll long long using namespace std; const int P=1e6; ; ; const i ...
- Tarjan求强连通分量、求桥和割点模板
Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using n ...
- 求强连通分量模板(tarjan算法)
关于如何求强连通分量的知识请戳 https://www.byvoid.com/blog/scc-tarjan/ void DFS(int x) { dfn[x]=lowlink[x]=++dfn_cl ...
随机推荐
- Java之创建线程的方式三:实现Callable接口
import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util ...
- Hough直线and圆环变换(如何检测直线、圆环)
1.霍夫变换 2.cv2.HoughLines() 返回值就是(ρ, θ).ρ 的单位是像素,θ 的单位是弧度.这个函数的第一个参 数是一个二值化图像,所以在进行霍夫变换之前要首先进行二值化,或者进行 ...
- idea代理上网
idea 代理上网 浏览器能够上网,idea无法下载jar 浏览器无法上网则配置浏览器代理 --------- start //------------------------浏览器代理完毕 idea ...
- leetcode中的sql
1 组合两张表 组合两张表, 题目很简单, 主要考察JOIN语法的使用.唯一需要注意的一点, 是题目中的这句话, "无论 person 是否有地址信息".说明即使Person表, ...
- java EE应用概述
1.javaEE应用的分层模型 不管是经典的Java EE架构,还是轻量级的Java EE架构,大致上都可以分为以下几层: Damain Object(领域对象)层:该层是由系列的POJO(普通的,传 ...
- Druid数据库连接池获取连接阻塞(转载)
一. 背景 17年公司有个项目组在南京做项目的时候,开发框架用的是spring boot ,数据库连接池用的是druid,但老是遇到socket read timeout的错误,不得已放 ...
- day66-CSS伪类选择器和伪元素选择器
1. 伪类选择器:hover 和 focus 比较常用. 1.1 hover:把鼠标移动到内容迈腾2020款TSI DSG舒适型的时候,字体变成了红色. html: <body> < ...
- 年近30的Java程序员为了达到月入三万的目标,都做了哪些准备?
1.我觉得像我这般年纪的(29岁),有相对扎实技术功底的(就不自谦了),对赚钱有着强烈欲望的程序员,应该定一个切实的小目标——五年内月入三万! 之所以要定这个目标,最主要的原因是老婆的批评刺痛了我—— ...
- oracle误删scott文件如何恢复
找到oracle的路径,一般是 某盘:\app\用户名\product\11.2.0\dbhome_1\RDBMS\ADMIN\scott.sql 这样找到scott.sql ,其中有恢复所有内容的S ...
- 关于redis的使用总结
简介 redis是一个开源的用c语言编写的数据库,但并不像常规的关系型数据库那样把数据存储在表中 , 而是像Java中的Map集合一样,存储的是一系列key=value键值对,redis属于NoSQL ...