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模板——求强连通分量的更多相关文章

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

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

  2. HDU 1269 迷宫城堡 tarjan算法求强连通分量

    基础模板题,应用tarjan算法求有向图的强连通分量,tarjan在此处的实现方法为:使用栈储存已经访问过的点,当访问的点离开dfs的时候,判断这个点的low值是否等于它的出生日期dfn值,如果相等, ...

  3. [学习笔记] Tarjan算法求强连通分量

    今天,我们要探讨的就是--Tarjan算法. Tarjan算法的主要作用便是求一张无向图中的强连通分量,并且用它缩点,把原本一个杂乱无章的有向图转化为一张DAG(有向无环图),以便解决之后的问题. 首 ...

  4. 【算法】Tarjan算法求强连通分量

    概念: 在有向图G中,如果两个定点u可以到达v,并且v也可以到达u,那么我们称这两个定点强连通. 如果有向图G的任意两个顶点都是强连通的,那么我们称G是一个强连通图. 一个有向图中的最大强连通子图,称 ...

  5. tarjan算法求强连通分量

    先上代码: #include <iostream> #include <cstring> #include <vector> #include <stack& ...

  6. HDU1269迷宫城堡(裸Tarjan有向图求强连通分量个数)

    迷宫城堡Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...

  7. tarjan 算法求强连通分量

    #include<bits/stdc++.h> #define ll long long using namespace std; const int P=1e6; ; ; const i ...

  8. Tarjan求强连通分量、求桥和割点模板

    Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using n ...

  9. 求强连通分量模板(tarjan算法)

    关于如何求强连通分量的知识请戳 https://www.byvoid.com/blog/scc-tarjan/ void DFS(int x) { dfn[x]=lowlink[x]=++dfn_cl ...

随机推荐

  1. 吴裕雄--天生自然MySQL学习笔记:MySQL 临时表

    MySQL 临时表在我们需要保存一些临时数据时是非常有用的.临时表只在当前连接可见,当关闭连接时,Mysql会自动删除表并释放所有空间. MySQL临时表只在当前连接可见,如果使用PHP脚本来创建My ...

  2. pywin32获得tkinter窗口句柄,并在上面绘图

    想实现用win32 API在tkinter窗口上画图,那么应该先获得tkinter窗口的句柄hwnd,然后再获得tkinter的设备hdc.尝试了FindWindow(),GetActiveWindo ...

  3. 半监督的GAN算法

    ImprovedGAN $ Loss = Loss_{supervised}   + \lambda * Loss_{unsupervised} $ 第二项形式与原始的GAN模型类似. 参考: Imp ...

  4. springCloud 常用组件总结

    本文浅谈只是对我自己初期认识这spring cloud的一个笔记. 微服务是一种架构风格和一种应对业务的架构策略.实现这种的技术方式很多.本文主要说spring cloud. spring cloud ...

  5. 在mybatis框架中,延迟加载与连表查询的差异

    1.引子 mybatis的延迟加载,主要应用于一个实体类中有复杂数据类型的属性,包括一对一和一对多的关系(在xml中用collection.association标签标识).这个种属性往往还对应着另一 ...

  6. 套接字详解(socket)

    用户认为的信息之间传输只是建立以两个应用程序上,实际上在TCP连接中是靠套接字来作为他们连接的桥梁. 那么什么是套接字呢? TCP用主机的IP地址加上主机上的端口号作为TCP连接的端点,这种端点就叫做 ...

  7. ant design vue 时间选择器只能到最大日期

    <a-date-picker :disabledDate="disabledEndDate"  style="width: 100%" placehold ...

  8. gcc -c xx.c 选项讲解

    -c选项表示编译.汇编指定的源文件(也就是编译源文件),但是不进行链接.使用-c选项可以将每一个源文件编译成对应的目标文件. 目标文件是一种中间文件或者临时文件,如果不设置该选项,gcc 一般不会保留 ...

  9. 十大经典排序算法(Javascript实现)

    前言 总括: 本文结合动图详细讲述了十大经典排序算法用Javascript实现的过程. 原文博客地址:十大经典排序算法 公众号:「菜鸟学前端」,回复「666」,获取一揽子前端技术书籍 人生有情泪沾衣, ...

  10. crf多表与基表系列化-自定义序列化深度表查询-断关联表关系-多表反序列化

    学习表关系的序列化和反序列表查询之前,新建项目的准备工作及环境搭建的配置. 配置:settings.py INSTALLED_APPS = [ # ... 'rest_framework', ] DA ...