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 ...
随机推荐
- HDU 2094产生冠军(set思维题)
Problem Description 有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛.球赛的规则如下:如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能 ...
- SQL 2005 带自增列 带外键约束 数据导入导出
1,生成建表脚本 选中要导的表,点右键-编写表脚本为-create到 ,生成建表脚本 2,建表(在新库),但不建外键关系 不要选中生成外键的那部分代码,只选择建表的代码 3,导数据,用SQL STU ...
- selenium浏览器内核监测处理
一.代码 from selenium.webdriver import Chrome from selenium.webdriver import ChromeOptions option = Chr ...
- beta函数与置信度估计
可信度的估计 二项分布中的\(p\) 服从Beta分布 $ {\rm beta}(\alpha, \beta)$, 密度函数 \(\frac1{B(\alpha, \beta)} x^{\alpha- ...
- UML-如何创建领域模型?
以当前迭代中所要设计的需求为界: 1.寻找概念类 2.将其绘制为类图 3.添加关联和属性
- Python语言学习:homework2
三级菜单 # Author:Crystal data = { '北京':{ "昌平":{ "沙河":["oldbay","test ...
- 题解 P1884 【[USACO12FEB]过度种植(银)Overplanting 】
什么,扫描线需要线段树? 那我第一个不干啊(其实是不会写) 这里介绍一种裸的扫描线: 我们根据x排序,对于相等的 \(x\) ,将 \(y\) 进入和退出分类讨论,然后全部放进set里面.每次 \(x ...
- quartz定时定时任务执行两次
quartz框架没问题. 流程: sping-quartz配置 <?xml version="1.0" encoding="UTF-8"?> < ...
- Django专题-AJAX
AJAX准备知识:JSON 什么是 JSON ? JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 JS ...
- swoole使用协程
协程:协程可以理解为纯用户态的线程,其通过协作而不是抢占来进行切换.相对于进程或者线程,协程所有的操作都可以在用户态完成,创建和切换的消耗更低.Swoole可以为每一个请求创建对应的协程,根据IO的状 ...