poj 2186 tarjan求强连通分量

蕾姐讲过的例题..玩了两天后才想起来做 貌似省赛之后确实变得好懒了...再努力两天就可以去北京玩了!

顺便借这个题记录一下求强连通分量的算法

1 只需要一次dfs 依靠stack来实现的tarjan算法 每次走到一个点 马上把它压入栈中 每次对与这个点相连的点处理完毕 判断是否low[u]==dfn[u] 若是 开始退栈 直到栈顶元素等于u才退出(当栈顶元素等于u也需要pop) 每次一起退栈的点属于同一个强连通分量 储存图可以用链式前向星也可以用邻接矩阵更可以用vector 蕾姐说不会超时 我信了

2 需要两次dfs的kosara 在输入图的时候需要搞出来一个反向图以便第二次dfs使用 开始进行一次dfs 每当一个点要离开的时候就将其压入栈中 当所有的点都被遍历后 从栈顶元素开始进行反向搜索 一次搜到的点属于同一个强连通分量 其实..也需要用到栈...

需要注意的是 当使用tarjan时 dfs时如果判断dfn[v]时已经有了值 在else中需要有if条件(!id[v])

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
#include<iostream>
#include<stack>
#include<vector>
using namespace std;
int n,m;
int id[10050];
int dfn[10050];
int low[10050];
int ans[10050];
int cd[10050];
int point[10050];
int num;
int cnt;
int tot;
vector<int >q[10050];
stack<int >s;
void init(){
for(int i=1;i<=n;i++)
{
    id[i]=0;
    dfn[i]=0;
    low[i]=0;
    ans[i]=0;
    cd[i]=0;
    point[i]=-1;
    q[i].clear();
}
num=cnt=tot=0;
while(!s.empty())
    s.pop();
}
void dfs(int u){
    dfn[u]=low[u]=++cnt;
    s.push(u);
    int v;
    int siz=q[u].size();
    for(int i=0;i<siz;i++)
    {
        v=q[u][i];
        if(!dfn[v])
        {
            dfs(v);
            low[u]=min(low[u],low[v]);

        }
        else if(!id[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u])
    {
        int temp=0;
        num++;
        while(!s.empty())
        {
            int v=s.top();
            s.pop();
            temp++;
            id[v]=num;
            if(v==u)
                break;
        }
        ans[num]=temp;
    }
}
struct node
{
    int v,nex;
};
node a[10050];
void add(int u,int v)
{
    a[tot].v=v;
    a[tot].nex=point[u];
    point[u]=tot;
    tot++;
}
void jt(){
for(int i=1;i<=n;i++)
{
    int siz=q[i].size();
    for(int k=0;k<siz;k++)
    {
        int v=q[i][k];
        if(id[v]!=id[i])
        {
            cd[id[i]]++;
        }
    }
}
}
void did(){
int can=0;
int p=-1;
for(int i=1;i<=num;i++)
{
    if(cd[i]==0)
    {
        can++;
        p=i;
    }
}
if(can==1)
{
    printf("%d\n",ans[p]);
}
else
    printf("0\n");
}
int main(){
while(cin>>n>>m)
{
    init();
    for(int i=1;i<=m;i++)
    {
        int u,v;
        cin>>u>>v;
        q[u].push_back(v);
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
            dfs(i);
    }
    jt();
    did();
}
}

  

时间: 2024-10-22 07:46:01

poj 2186 tarjan求强连通分量的相关文章

POJ 2186 Popular Cows --强连通分量

题意:给定一个有向图,问有多少个点由任意顶点出发都能达到. 分析:首先,在一个有向无环图中,能被所有点达到点,出度一定是0. 先求出所有的强连通分支,然后把每个强连通分支收缩成一个点,重新建图,这样,这个有向图就变成了一个有向无环图. 在这个新的图中,只需知道出度为0的点有几个即可. 如果出度为0的点超过1个,则输出0:否则输出出度为0的点所代表的那个强连通分支的分量数即可. 用Tarjan求强连通分量 代码: #include <iostream> #include <cstdio&g

UESTC 901 方老师抢银行 --Tarjan求强连通分量

思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个DAG(有向无环图),然后跑一遍DFS,不断加上遍历点的权值,如果到了网吧,则更新一遍答案,因为可以出去了. 求强连通分量时,如果low[u] == dfn[u],说明形成了一个新的强连通分量,且根为u.具体求强连通分量见:http://www.cnblogs.com/whatbeg/p/377642

CCF 高速公路 tarjan求强连通分量

问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路. 现在,大臣们帮国王拟了一个修高速公路的计划.看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能.如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对. 国王想知道,在大臣们给他的计划中,有多少个便利城市对. 输入

UVALive 4262——Trip Planning——————【Tarjan 求强连通分量个数】

Road Networks Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVALive 4262 Description There is a road network comprised by M<tex2html_verbatim_mark> roads and N<tex2html_verbatim_mark> cities.

hdu 1269 tarjan求强连通分量

tarjan求强连通分量的裸题复习,直接上代码: 1 #include <stack> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int N = 10001; 7 const int M = 100000; 8 int dfn[N], low[N], head[N]; 9 bool inStack[N]; 10 int n, m, e, cnt, dfs_clock

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

Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using namespace std; const int maxn = 1e3 + 10; const int maxm = 330000 + 10; struct EDGE{ int v, nxt; }Edge[maxm]; int Head[maxn], cnt; int DFN[maxn], LOW[maxn],

tarjan求强连通分量(模板)

https://www.luogu.org/problem/P2341 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=50010; int pre[maxn],other[maxn],last[maxn],l; int n,m; int dfn[maxn],low[maxn],ans[maxn],st[maxn],belong[maxn

POJ-3180 The Cow Prom(tarjan求强连通分量)

题目链接:http://poj.org/problem?id=3180 题目大意:求一个有向图的强连通分量 算法:求强连通分量首选tarjan算法 这里简单说一下tarjan的思路 时间戳是什么:在搜索时访问的最早时间 维护dfn[u]表示u的时间戳 low[u]表示u点所能回到的最早的祖先的时间戳 开一个栈,把搜索的点入栈.搜索时遇到已经搜过的点,取low[u]和dfn[v]的最小值,回溯时取low[u]和low[v]的最小值(标记上传)传到dfn[u]<=low[u]时表示已经回溯到最上面的

【BZOJ1051】1051: [HAOI2006]受欢迎的牛 tarjan求强连通分量+缩点

Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎.你的任务是求出有多少头牛被所有的牛认为是受欢迎的. Input 第一行两个数N,M. 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B) Output 一个数,即有多少头牛被所有的牛认为是受欢迎的. Sample Input 3 3