强连通分量

模板(强联通分量个数+缩点)

#include<iostream>
#include<cstdio>
#define MAXn 100000
#define MAXm 2000000
using namespace std;
int dfn[MAXn],low[MAXn],head[MAXm],st[MAXn],belong[MAXn];
bool in_st[MAXn];
int ans,n,m,num,s_num,cnt,group_num;
struct node{
int to,pre;
}e[MAXm];
void Insert(int from,int to){
e[++num].pre=head[from];
e[num].to=to;
head[from]=num;
}
void group(int u){
cnt++;st[++s_num]=u;dfn[u]=low[u]=cnt;in_st[u]=;
for(int i=head[u];i;i=e[i].pre){
int v=e[i].to;
if(!dfn[v]){
group(v);
if(low[v]<low[u])low[u]=low[v];
}
else if(dfn[v]<low[u])
if(in_st[v])
low[u]=dfn[v];
}
if(dfn[u]==low[u]){
group_num++;
while(st[s_num]!=u){
in_st[st[s_num]]=;
belong[st[s_num]]=group_num;
s_num--;
}
in_st[u]=;s_num--;
belong[u]=group_num;
}
}
int main(){
freopen("Tarjan_group.txt","r",stdin);
scanf("%d%d",&n,&m);int x,y;
for(int i=;i<=m;i++){
scanf("%d%d",&x,&y);
Insert(x,y);
}
for(int i=;i<=n;i++){
if(!dfn[i])group(i);
}
for(int i=;i<=n;i++){
printf("%d ",belong[i]);
}printf("\n%d",group_num);
}

Tarjan_group模板

例题

poj3114  Countries in War

跑一边强连通分量,搞出缩点,求缩点间的最短路

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxm 250010
#define maxn 510
int head[maxm],dfn[maxn],low[maxn],st[maxn],belong[maxn],blong[maxn][maxn];
int n,m,num,order,cnt,s_num,num_g,dis[maxn][maxn];
int nw[][];
bool in_st[maxn];
struct node{
int to,v,pre;
}e[maxm];
void Insert(int from,int to,int v){
e[++num].to=to;
e[num].pre=head[from];
e[num].v=v;
head[from]=num;
}
void group(int u){
cnt++;dfn[u]=low[u]=cnt;st[++s_num]=u;in_st[u]=;
for(int i=head[u];i;i=e[i].pre){
int v=e[i].to;
if(!dfn[v]){
group(v);
if(low[v]<low[u])low[u]=low[v];
}
else if(dfn[v]<low[u])
if(in_st[v])low[u]=dfn[v];
}
if(low[u]==dfn[u]){
num_g++;
while(st[s_num]!=u){
blong[num_g][++blong[num_g][]]=st[s_num];
belong[st[s_num]]=num_g;
in_st[st[s_num]]=;
s_num--;
}belong[u]=num_g;
blong[num_g][++blong[num_g][]]=u;
in_st[u]=;s_num--;
}
}
int main(){
freopen("Tarjan_group.txt","r",stdin);
int nm,nn;
while(){
cin>>n>>m;
if(n==&&m==)break;
memset(dfn,,sizeof(dfn));
memset(head,,sizeof(head));
memset(low,,sizeof(low));
memset(st,,sizeof(st));
memset(e,,sizeof(e));
memset(belong,,sizeof(belong));
memset(blong,,sizeof(blong));
num_g=;s_num=;cnt=;
int x,y,z;
memset(nw,/,sizeof(nw));
memset(dis,/,sizeof(dis));
for(int i=;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
Insert(x,y,z);
nw[x][y]=z;
}
for(int i=;i<=n;i++){
if(!dfn[i])group(i);
} /*for(int i=1;i<=n;i++)
cout<<belong[i]<<' ';cout<<endl<<endl;*/
for(int i=;i<=n;i++){
dis[i][i]=;
nw[i][i]=;
}
for(int k=;k<=n;k++){
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
if(i!=j&&i!=k&&k!=j)
nw[i][j]=min(nw[i][j],nw[i][k]+nw[k][j]);
}
}
}
for(int i=;i<=num_g;i++){
for(int j=;j<=num_g;j++){//找到两个缩点
if(i!=j){
for(int k=;k<=blong[i][];k++){
for(int l=;l<=blong[j][];l++){
if(k!=l)
dis[i][j]=min(dis[i][j],nw[blong[i][k]][blong[j][l]]);
}
}
}
}
}
int p;
scanf("%d",&p);
for(int i=;i<=p;i++){
scanf("%d%d",&x,&y);
if(dis[belong[x]][belong[y]]>=)cout<<"Nao e possivel entregar a carta"<<endl;
else cout<<dis[belong[x]][belong[y]]<<endl;
}
}
}

TLE

#include<cstring>
#include<cstdio>
#include<iostream>
#define Max 505
using namespace std;
int map[Max][Max];
struct Edge{
int to,w;
int next;
}edge[Max * Max];
int head[Max],tol;
void add(int u,int v,int w){
edge[tol].to=v;
edge[tol].w=w;
edge[tol].next=head[u];
head[u]=tol++;
}
int dfn[Max],low[Max],Stack[Max],belong[Max];
int bcnt,time,top,instack[Max];
void tarjan(int u){
dfn[u]=low[u]=++time;
Stack[top++]=u;
instack[u]=true;
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else{
if( instack[v])
low[u] = min(low[u], dfn[v]);
}
}
int v;
if(low[u] == dfn[u]){
bcnt++;
do{
v = Stack[--top];
instack[v] = false;
belong[v] = bcnt;
}while(u != v);
}
}
int main(){
int n,m;
int v,u,w;
while(~scanf("%d%d", &n,&m)){
if(!n && !m) break;
memset(head,-,sizeof(head));
tol=;
for(int i=;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
top=time=bcnt=;
for(int i=;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int i=;i<=n;i++){
for(int j=;j<=n;j++)
if(i==j)
map[i][j]=;
else map[i][j]=0x3f3f3f3f;
} for(u=;u<=n;u++) {
for(int j=head[u];j!=-;j=edge[j].next) {
v=edge[j].to;
w=edge[j].w;
if(belong[u]!=belong[v])
map[belong[u]][belong[v]]=min(map[belong[u]][belong[v]],w);
}
}
for(int k=;k<=bcnt;k++){
for(int i=;i<=bcnt;i++){
for(int j=;j<=bcnt;j++)
if(map[i][j]>map[i][k]+map[k][j])
map[i][j]=map[i][k]+map[k][j];
}
}
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&u,&v);
if(map[belong[u]][belong[v]] == 0x3f3f3f3f)
printf("Nao e possivel entregar a carta\n");
else
printf("%d\n",map[belong[u]][belong[v]]);
}
printf("\n");
}
return ;
}

AC

poj1236Network of Schools

题意:一个包含1-n号学校的网络,每个学校有个软件分发列表,当学校拿到软件时会把软件分发给列表里的学校。 
问1:一个新软件出现时初始化情况至少需要给多少个学校才能让它到达整个网络? 
问2:至少需要添加多少个名单才能使从任意一个学校开始分发都能充满整个网络?

也就是: 
—给定一个有向图,求:

1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点

2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点

DAG上面有多少个入度为0的顶点,问题1的答案就是多少 
在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少

加边的方法:假定有 n 个入度为0的点,m个出度为0的点,max(m,n)就是第二个问题的解

#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 110
#define maxm (maxn*(maxn - 1)/2)
int n,num,cnt,num_g,num_in0,num_out0;
int in[maxn],out[maxn],head[maxm],belong[maxn],dfn[maxn],low[maxn],st[maxn],s_num;
int blong[maxn][maxn],nmp[maxn][maxn];
bool s_in[maxn],vis[maxn][maxn];
struct node{
int to,pre;
}e[maxm];
void Insert(int from,int to){
e[++num].pre=head[from];
e[num].to=to;
head[from]=num;
}
void group(int u){
cnt++;dfn[u]=low[u]=cnt;st[++s_num]=u;s_in[u]=;
for(int i=head[u];i;i=e[i].pre){
int v=e[i].to;
if(dfn[v]==){
group(v);
low[u]=min(low[u],low[v]);
}
else if(dfn[v]){
/*if(s_in[v])*/low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
num_g++;
while(st[s_num]!=u){
s_in[st[s_num]]=;
belong[st[s_num]]=num_g;
blong[num_g][++blong[num_g][]]=st[s_num];
s_num--;
}
s_num--;belong[u]=num_g;
blong[num_g][++blong[num_g][]]=u;
}
}
int main(){
freopen("1236.txt","r",stdin);
scanf("%d",&n);int a;
for(int i=;i<=n;i++){
while(){
scanf("%d",&a);
if(a==)break;
Insert(i,a);
}
}
for(int i=;i<=n;i++){
if(dfn[i]==)group(i);
} /*for(int i=1;i<=num_g;i++){//枚举每个缩点
for(int j=1;j<=blong[i][0];j++){//枚举缩点里的每个点
int u=i;
for(int k=head[blong[i][j]];k;k=e[k].pre){
int v=belong[e[k].to];
if(vis[u][v]==0&&v!=u){
vis[u][v]=1;in[v]++;out[u]++;
}
}
}
}*/
for(int u=;u<=n;u++){
for(int i=head[u];i;i=e[i].pre){
int v=e[i].to;
if(belong[u]!=belong[v]){
in[belong[v]]++;
out[belong[u]]++;
}
}
}
for(int i=;i<=num_g;i++){
if(in[i]==)num_in0++;
if(out[i]==)num_out0++;
}
cout<<num_in0<<endl;
if(num_g==)cout<<;
else cout<<max(num_in0,num_out0);
return ;
}

wa

图论1 Tarjan算法的更多相关文章

  1. 图论初步-Tarjan算法及其应用

    暑假刷了一堆Tarjan题到头来还是忘得差不多. 这篇博客权当复习吧. 一些定义 无向图 割顶与桥 (划重点) 图G是连通图,删除一个点表示删除此点以及所有与其相连的边. 若删除某点u后G不再连通,那 ...

  2. 图论:Tarjan算法

    在有向图中,若两点至少包含一条路径可以到达,则称两个顶点强连通,若任意两个顶点皆如此,则称此图为强联通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected com ...

  3. 『图论』有向图强连通分量的Tarjan算法

    在图论中,一个有向图被成为是强连通的(strongly connected)当且仅当每一对不相同结点u和v间既存在从u到v的路径也存在从v到u的路径.有向图的极大强连通子图(这里指点数极大)被称为强连 ...

  4. 【算法•日更•第二十八期】图论:强连通+Tarjan算法(一)

    ▎前言 一直都想学习这个东西,以为很难,结果发现也不过如此. 只要会些图论的基础就可以了. ▎强连通 ☞『定义』 既然叫强连通,那么一定具有很强的连通性. 强连通:就是指在一个有向图中,两个顶点可以互 ...

  5. ACM(图论)——tarjan算法详解

    ---恢复内容开始--- tarjan算法介绍: 一种由Robert Tarjan提出的求解有向图强连通分量的线性时间的算法.通过变形,其亦可以求解无向图问题 桥: 割点: 连通分量: 适用问题: 求 ...

  6. 图论-强连通分量-Tarjan算法

    有关概念: 如果图中两个结点可以相互通达,则称两个结点强连通. 如果有向图G的每两个结点都强连通,称G是一个强连通图. 有向图的极大强连通子图(没有被其他强连通子图包含),称为强连通分量.(这个定义在 ...

  7. Light OJ - 1026 - Critical Links(图论-Tarjan算法求无向图的桥数) - 带详细注释

     原题链接   无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 也可以先用Tajan()进行dfs算出所有点 的low和dfn值,并记录dfs过程中每个 点的父节点:然后再把所有点遍历一遍 ...

  8. 强连通分量的Tarjan算法

    资料参考 Tarjan算法寻找有向图的强连通分量 基于强联通的tarjan算法详解 有向图强连通分量的Tarjan算法 处理SCC(强连通分量问题)的Tarjan算法 强连通分量的三种算法分析 Tar ...

  9. tarjan算法 POJ3177-Redundant Paths

    参考资料传送门 http://blog.csdn.net/lyy289065406/article/details/6762370 http://blog.csdn.net/lyy289065406/ ...

随机推荐

  1. 【windows】如何让一个程序开机自启动

    windows的开机自启动也是将一个程序放在文件夹下即可,将应用程序或者快捷方式放在如下文件夹下,即可实现开机自启动 C:\ProgramData\Microsoft\Windows\Start Me ...

  2. Django的模型层(2)---多表操作

    多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是一对 ...

  3. IOS 关于 NSUserDefault

    转载 并不是所有的东西都能往里放的.NSUserDefaults只支持: NSString, NSNumber, NSDate, NSArray, NSDictionary.   NSUserDefa ...

  4. iOS 开发实践之 Auto Layout

    原:http://xuexuefeng.com/autolayout/?utm_source=tuicool 本文是博主 iOS 开发实践系列中的一篇,主要讲述 iOS 中 Auto Layout(自 ...

  5. png24 png8 jpeg与gif

    png24无损压缩,支持透明,有8位布尔透明通道,支持半透明,生成的图片品质最高,也最大 png8支持透明,有1位布尔透明通道,要么透明.要么半透明,生成的图片很小,只支持256色 jpeg有损压缩, ...

  6. BZOJ 4519 [CQOI2016]不同的最小割

    这道题目很奇怪. 为什么奇怪?因为这道题用了一种叫分治最小割/最小割树的玩意. 以前从来没有见过这东西. 推荐一个讲这玩意的博客 写起来还是很顺手的. #include<iostream> ...

  7. python基本模块相关信息

    系统相关的信息模块: import sys sys.argv 是一个 list,包含所有的命令行参数. sys.stdout sys.stdin sys.stderr 分别表示标准输入输出,错误输出的 ...

  8. ffmpeg去水印

    1.用potplayer打开有水印的视频文件,截图一张待用.2.用IrfanView打开保存的图片,调整到100%大小,按住鼠标左键框选水印位置,记下标题“Selection:”右边的4组数字.3.f ...

  9. 在你的网站中使用 AdSense广告

    下面介绍了如何使用Google的AdSense来为你的网站设置广告.基本内容包括: 创建一个AdSense账号,你必须18岁以上,有一个Google账号以及地址 你的网站必须已经被激活,并且你的网站内 ...

  10. darknet YOLOv2安装及数据集训练

    一. YOLOv2安装使用 1. darknet YOLOv2安装 git clone https://github.com/pjreddie/darknetcd darknetmake或到网址上下载 ...