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. 基于表单的web暴力破解

    暴力破解 概述 连续性尝试+字典+自动化 如果一个网站没有对登录接口实施防暴力破解的措施,或者实施了不合理的措施,则该网站存在暴力破解漏洞. 是否要求用户设置了复杂的密码 是否每次认证都是用安全的验证 ...

  2. 移动端— position: fixed;固定定位解决方案

    这里有个关键的东西叫做viewport,你经常在页面的头部里可以见到它: <meta name="viewport" content="width=device-w ...

  3. Spring DATA Neo4J(一)

    Spring DATA Neo4J——简介 Spring Framework提供了一下模块来处理基于Java的应用程序的DAO层 Spring JDBC Spring ORM Spring DATA ...

  4. Go 验证是否字符串包含中文

    发现一个验证字符串是否包含中文滴时候,一个比正则更好使滴方法,而且是golang 自带滴验证. 不需要自己写正则验证,代码如下: package main import ( "fmt&quo ...

  5. goweb-动作

    go-模板引擎 动作 Go 模板的动作就是一些嵌入到模板里面的命令,这些命令在模板中需要放到两个 大括号里{{ 动作 }},之前我们已经用过一个很重要的动作:点(.),它代表了传递给模 板的数据.下面 ...

  6. SSh三大框架的作用

    一.详细分析spring+hibernate+struts作用? 1.struts是框架的表现层,Struts是对MVC构架的具体实现 Struts的MVC三层结构: (1)视图层:Struts采用J ...

  7. 使用itop4412开发板单独编译驱动模块

    上面我们的驱动是放在了内核源码的目录下来实现的编译成驱动模块,很多时候我们都是拿到一个驱动源码,不需要把他放到内核源码里面,而是直接把他编译成驱动模块,下面我们来讲下实现方法,我们还是以蜂鸣器的驱动为 ...

  8. JS—Function类型

    1.函数的声明方式有三种普通函数的声明方式function box(num1,num2){ return num1+num2;}alert(box(1,2)); 使用变量初始化函数var box = ...

  9. css,js,jquery的载入方式和属性控制

    本文章主要总结了css,js,jQuery在编写程序时的载入方式,与属性控制方式html和css共同组成了一个最基础的网页,js为标签样式提供动态效果 一,css的载入方式与属性控制 1.1,css引 ...

  10. Photoshop和Halcon如何锐化彩色图像不伤其颜色

    锐化图像是摄影中的一步重要操作. 锐化是通过颜色提纯达到锐化的目的.一旦锐化过度,照片很容易就会出现不自然的色斑,或溢色效果. 我们以Photoshop中的“USM锐化滤镜”为例:(为了使效果明显,我 ...