强连通分量

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

#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. 使用nginx+nginx-rtmp-module+ffmpeg搭建流媒体服务器

    参考: 1,使用nginx+nginx-rtmp-module+ffmpeg搭建流媒体服务器笔记(一)http://blog.csdn.net/xdwyyan/article/details/4319 ...

  2. [IR课程笔记]Hyperlink-Induced Topic Search(HITS)

    两个假设 1. 好的hub pages: 好的对某个主题的hub pages 链接许多好的这个主题的authoritative pages. 2. 好的authoritative pages: 好的对 ...

  3. VIM中使用tab键自动完成(vim tab键自动补全 )插件supertab

    supertab.vmb 这个插件好好用, Tab自动补全 http://www.vim.org/scripts/script.php?script_id=1643 安装步骤: 1.下载 supert ...

  4. Django+ajax+jsonp实现借口调用文本处理

    首页 提交 <script src="/static/jquery-2.1.4.min.js"></script> <script type=&quo ...

  5. myeclipse 安装flex插件后变为中文 修改配置文件切换到英文界面

    解决办法: 1. cmd 敲命令进入安装目录,运行myeclipse.exe -nl en后,启动为英文 在安装目录下新建txt,改名为myeclipse.bat,将上面那行命令写入保存,再发送快捷方 ...

  6. 带动画效果的jQuery手风琴

    带动画效果的jQuery特效手风琴是一款带动画效果的手风琴作品,非常实用,可以用在新闻列表.FAQ等模块,默认的是打开第一个选项,查看其它的时候直接点击加号按钮就展开. 源码地址:http://www ...

  7. NOIP 2016【蚯蚓】

    好吧,我承认我是个智障-- 这道题一眼看上去就是个堆,然而实际上有单调性. 注意到,如果 \(q = 0\) 的话,将蚯蚓的左右两边分开丢进两个队列中,则两个队列都是单调不增的,因为每次取出的蚯蚓长度 ...

  8. centos7搭建mysql-5.7.22主从复制

    mysql7.7.22主从复制 本项目是根据真实环境搭建编写出文档,文档中的目录也是根据自己公司环境所创建.公司原来是一台服务器搭建的数据库(5.7.22),由于业务的扩展需要搭建一台从服务器,减轻主 ...

  9. static修饰类的作用

    Java里面static一般用来修饰成员变量或函数.但有一种特殊用法是用static修饰内部类,普通类是不允许声明为静态的,只有内部类才可以.被static修饰的内部类可以直接作为一个普通类来使用,而 ...

  10. dmidecode 命令

    dmidecode                                                 #  查看全面硬件信息dmidecode | grep "Product ...