强连通分量

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

#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. Ubuntu PPPoE拨号上网指定网卡

    Just follow these steps: Check that the ethernet cable is properly connected Open Terminal Run sudo ...

  2. TensorFlow运行时出现warning如何设置禁止打印方法

    有时候运行TensorFlow时比较烦人,经常报一些warning或者版本更新了之类的一些警告,如下: 那么如何去掉或者说不显示这些东西呢,可以通过简单添加几行代码搞定,来看一下. 这样就不会报警告了 ...

  3. ubuntu 更新软件命令

    安装软件最好加权限(sudo) --default-timeout=100 设置超时时间100秒 install -U setuptools 表示更新安装setuptools sudo pip3 -- ...

  4. JETSON TK1 ~ 控制GPIO

    首先建立个存放gpio代码的文件夹,CD到该文件夹. git clone git://github.com/derekmolloy/boneDeviceTree/ 解压后会出现几个文件 GPIO文件夹 ...

  5. C#winform的datagridview设置选中行

    this.dataGridView1.CurrentCell = this.dataGridView1[colIndex, rowIndex];this.dataGridView1.BindingCo ...

  6. Gemini.Workflow 双子工作流入门教程三:定义流程:流程节点、迁移条件参数配置

    简介: Gemini.Workflow 双子工作流,是一套功能强大,使用简单的工作流,简称双子流,目前配套集成在Aries框架中. 下面介绍本篇教程:定义流程:流程节点.迁移条件参数配置. 一.普通节 ...

  7. vue应用示例

    1 . 实现轮播图 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset=&q ...

  8. C# 计时器 以“天时分秒毫秒”形式动态增加显示

    参考:http://zhidao.baidu.com/link?url=j-jxQJenrO54BSKJ_IkXWbhdDqbVLUyyenjjSGs8G0xdisgBZ0EMhzyWgARSFct6 ...

  9. js修改div标签中的内容

    <div id='divId'>初始文字</div> <script> $(document).ready(function(e){ $('#divId').htm ...

  10. python根据圆的参数方程求圆上任意一点的坐标

    from math import cos, sin,pi x0,y0=0,0 r=4.0 angle=-25 x1 = x0 + r * cos(angle * pi / 180) y1 = y0 + ...