POJ2186 Popular Cows【Tarjan】【强连通分量】

题目连接:

http://poj.org/problem?id=2186

题目大意:

每头奶牛都希望自己成为最欢迎的那头牛。给你N头牛,M个崇拜关系(A,B)。意思是牛A

崇拜牛B。特别是,如果牛A崇拜牛B,牛B崇拜牛C,那么牛A也崇拜牛C。那么问题来了:

请计算出被所有牛崇拜的牛的个数。

思路:

把崇拜关系(A,B)看做是一条有向边,并且,我们发现牛的崇拜关系具有传递性。那么只要

牛A有一条路径连向牛B,就可以判定牛A崇拜牛B。于是,被所有牛崇拜的牛就是所有的点

都存在一条路径连向它的有向路径。这道题中,将原图强连通分量缩点后构成了DAG,那么

如果新图中出度为0的点只有一个,则有解,为该出度为0的点的强连通分量中点的个数。若

出度为0的点的个数不止一个,那么无解。因为至少有两头牛互相不崇拜。

之前用Kosaraju算法来做,这次用Tarjan算法来做。

描述一下Tarjan算法:

对原图进行优先搜索,每个强连通分量是原图深度优先搜索的子树。那么我们就可以通过确

定每个强连通分量子树的根,根据这些根,从树的最底层开始,一个一个去处强连通分量。

使用两个数组:dfn[v]来表示顶点v被访问的时间,low[v]表示为顶点v邻接的未删除的顶点

u的low[u]和顶点v的low[v]的最小值(low[v]初始化为dfn[v])。这是为了使同一强连通分量的

low[]值都相同,且值与该强连通分量的根的访问时间dfn[]相等,从而就确定了强连通分量

的根和其属于强连通分量的点。

这样,如果发现了low[v] == dnf[v],那么,该点v就是一个强连通分量的根。因为如果该点

v不是强连通分量的根,那么一定属于另一个强连通分量,而且该点v的根就是当前顶点v的祖

宗,那就存在包含当前顶点v到其祖宗的回路,可知顶点v的low[v]值一定是比顶点v的访问时

间dfn[v]更小的值,应为顶点v所在强连通分量的根的dfn[]值。

确定了强连通分量的根后,怎么来取出强连通分量呢?

如果当前节点v为一个强连通分量的根,那么它的强连通分量一定是以该节点v为根节点的子

树。在深度优先遍历的时候维护一个堆栈,每次访问一个新节点,就压入堆栈。由于当前节

点v是这个强连通分量中最先压入堆栈的,那么在当前节点v以后压入堆栈并且仍在堆栈中的

节点都属于这个强连通分量。假设一个节点u在当前节点v压入堆栈后压入并且还存在,同时

节点u不属于该强连通分量。那么一定属于另一个强连通分量,但当前节点v是节点u的根的

祖宗,那么这个强连通分量在之前已经被取出。

具体做法:

(1)访问一个没有被访问过的节点v;否则结束。

(2)初始化dfn[v]和low[v]。

对于节点v的所有邻接顶点u:

1.如果没有访问过,转到步骤(2),同时维护low[v]。

2.如果访问过,但没有删除,维护low[v]。

如果low[v] == dfn[v],那么取出相应的强连通分量。

参考:ACM-ICPC程序设计系列——图论及应用 P115~117

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 10010;
const int MAXM = 50050;

struct EdgeNode
{
    int to;
    int next;
}Edges[MAXM];

int Head[MAXN],vis[MAXN],low[MAXN];
int dfn[MAXN],Stack[MAXN],outdegree[MAXN],Count[MAXN],m,id;

void AddEdges(int u,int v)
{
    Edges[id].to = v;
    Edges[id].next = Head[u];
    Head[u] = id++;
}

int TarBFS(int pos,int lay,int &scc)
{
    vis[pos] = 1;
    low[pos] = lay;     //初始为开始时间
    dfn[pos] = lay;     //初始为开始时间
    Stack[++m] = pos;   //将当前未处理节点入栈,回溯时可以判断栈顶到栈中的结点是否为同一个强连通分量
    for(int i = Head[pos]; i != -1; i = Edges[i].next)  //枚举每一条边
    {
        if(!vis[Edges[i].to])
            TarBFS(Edges[i].to,++lay,scc);
        if(vis[Edges[i].to] == 1)
            low[pos] = min(low[pos],low[Edges[i].to]);
    }

    if(dfn[pos] == low[pos])    //缩点,low[]相同的结点属于同一个强连通分量
    {
        ++scc;
        do
        {
            Count[scc]++;       //强连通分量内的点数
            low[Stack[m]] = scc;
            vis[Stack[m]] = 2;
        }while(Stack[m--] != pos);
    }
    return 0;
}

int Tarjan(int N)
{
    int scc = 0, temp = 0, ans, lay = 1;
    m = 0;
    memset(vis,0,sizeof(vis));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    for(int i = 1; i <= N; ++i)
        if(vis[i] == 0)
            TarBFS(i,lay,scc);

    for(int i = 1; i <= N; ++i)
    {
        for(int j = Head[i]; j != -1; j = Edges[j].next)
            if(low[i] != low[Edges[j].to])
            {
                outdegree[low[i]] = 1;
                break;
            }
    }

    for(int i = 1;i <= scc; ++i)
    {
        if(! outdegree[i])
        {
            if(++temp > 1)
                break;
            ans = Count[i];
        }
    }

    if(temp != 1)
        return 0;
    return ans;
}
int main()
{
    int N,M,u,v;
    while(~scanf("%d%d",&N,&M))
    {
        memset(Head,-1,sizeof(Head));
        memset(outdegree,0,sizeof(outdegree));
        memset(Count,0,sizeof(Count));
        id = 0;
        for(int i = 0; i < M; ++i)
        {
            scanf("%d%d",&u,&v);
            AddEdges(u,v);
        }
        int ans = Tarjan(N);
        printf("%d\n",ans);
    }

    return 0;
}
时间: 2024-10-09 04:44:17

POJ2186 Popular Cows【Tarjan】【强连通分量】的相关文章

POJ2186 Popular Cows 【强连通分量Kosaraju】

Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23445   Accepted: 9605 Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M &l

POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】

Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23445   Accepted: 9605 Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M &l

[POJ2186]Popular Cows(强连通分量)

题目链接:http://poj.org/problem?id=2186 给定n个点m条边,求某点使得其他点都有通向它的一条路径,计算这个点集的大小. 强连通分解后求出度为0的连通分量的个数,如果有且仅有一个连通分量出度为1,则统计这个连通分量中点的数目. 遍历所有点的出边指向的点,判断这两个点是否属于同一个连通分量,记录每个连通分量中的点的数目. 1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip&

poj 2186 Popular Cows 【强连通分量Tarjan算法 + 树问题】

题目地址:http://poj.org/problem?id=2186 Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 27496   Accepted: 11059 Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows

POJ 2186 Popular Cows (强连通分量)

POJ 2186 Popular Cows 链接:http://poj.org/problem?id=2186 题意:每头奶牛都梦想着成为牧群中最受奶牛仰慕的奶牛.在牧群中,有N 头奶牛,1≤N≤10,000,给定M 对(1≤M≤50,000)有序对(A, B),表示A 仰慕B.由于仰慕关系具有传递性,也就是说,如果A 仰慕B,B 仰慕C,则A 也仰慕C,即使在给定的M 对关系中并没有(A, C).你的任务是计算牧群中受每头奶牛仰慕的奶牛数量. 思路:首先可以知道,在同一个强连通分量内的点一定互

Poj 2186 Popular Cows(Tarjan 强连通缩点)

传送门:Poj 2186 题意:给你n头牛,m种关系,A牛认为B牛是popular的,B牛认为C牛是popular的,则A也认为C是popular的,问最终有几头被所有牛认为是popular的牛 题解:强连通缩点基础题(虽然我Tarjan和缩点都是对的,但是最终讨论判断的时候写垮了(写了3天....还不是你懒!!!!过年划水这么多天缩点后找出度为零的点个数.然后讨论是否有这样子的点,如果没有则全都是(整个都是强连通图),如果只有一个,那么那个强连通分量所含的牛的个数就是所求解,如果有多个那么都是

POJ 2186:Popular Cows(强连通分量)

[题目链接] http://poj.org/problem?id=2186 [题目大意] 给出一张有向图,问能被所有点到达的点的数量 [题解] 我们发现能成为答案的,只有拓扑序最后的SCC中的所有点, 那么我们从其中一个点开始沿反图dfs,如果能访问到全图, 则答案为其所在SCC的大小,否则为0. [代码] #include <cstdio> #include <algorithm> #include <vector> #include <cstring>

POJ2186 Popular Cows [tarjan 缩点]

Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 31241   Accepted: 12691 Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M &

强连通分量tarjan缩点——POJ2186 Popular Cows

这里的Tarjan是基于DFS,用于求有向图的强联通分量. 运用了一个点dfn时间戳和low的关系巧妙地判断出一个强联通分量,从而实现一次DFS即可求出所有的强联通分量. §有向图中, u可达v不一定意味着v可达u.    相互可达则属于同一个强连通分量    (Strongly Connected Component, SCC) §有向图和它的转置的强连通分量相同 §所有SCC构成一个DAG(有向无环图) dfn[u]为节点u搜索的次序编号(时间戳),即首次访问u的时间 low[u]为u或u的

poj2186 Popular Cows --- 强连通

给一个有向图,问有多少结点是其他所有结点都可以到达的. 等价于,在一个有向无环图上,找出度为0 的结点,如果出度为0的结点只有一个,那么这个就是答案,如果大于1个,则答案是0. 这题有环,所以先缩点.求唯一出度为0的强连通分量. #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<iostream> #define inf 0x3f3f3f3f