POJ(2186)强连通分量分解

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int MAX_N=10005;
vector<int> G[MAX_N];
vector<int> rG[MAX_N];//存储边反向之后的图
vector<int> PostOrder;//存储图的后序遍历
int V,E;
bool used[MAX_N];
int comp[MAX_N];//存储每个结点所属的连通分量
void addEdge(int u,int v)
{
    G[u].push_back(v);
    rG[v].push_back(u);
}
void dfs(int u)
{
    used[u]=true;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(!used[v])
            dfs(v);
    }
    PostOrder.push_back(u);
}

void rdfs(int u,int k)
{
    used[u]=true;
    comp[u]=k;
    for(int i=0;i<rG[u].size();i++)
    {
        int v=rG[u][i];
        if(!used[v])
            rdfs(v,k);
    }
}

int scc()
{
    memset(used,false,sizeof(used));
    for(int i=1;i<=V;i++)
    {
        if(!used[i])
            dfs(i);
    }
    memset(used,false,sizeof(used));
    int k=0;
    for(int i=PostOrder.size()-1;i>=0;i--)
    {
        int v=PostOrder[i];
        if(!used[v])
            rdfs(v,k++);
    }
    return k;
}
int main()
{
    scanf("%d %d",&V,&E);
    for(int i=0;i<E;i++)
    {
        int u,v;
        scanf("%d %d",&u,&v);
        addEdge(u,v);
    }
    int n=scc();
    int u=0,num=0;
    for(int i=1;i<=V;i++)
    {
        if(comp[i]==n-1)//可能的答案必为最后一个强连通分量
        {
            u=i;
            num++;
        }
    }
    memset(used,false,sizeof(used));
    rdfs(u,0);//若最后一个连通分量的中的一点,能按反向边将所有结点遍历则该联通分量为答案
    for(int i=1;i<=V;i++)
    {
        if(!used[i])
        {
            num=0;
            break;
        }
    }
    printf("%d\n",num);
    return 0;
}
时间: 2024-10-21 17:20:50

POJ(2186)强连通分量分解的相关文章

【强连通分量分解】

摘自<挑战程序设计>4.3.1 [强连通分量分解原理] 对于一个有向图顶点的子集S,如果在S内任取两个顶点u和v,都能找到一条从u到v的路径,那么就称S是强连通的.如果在强连通的顶点集合S中加入其他任意顶点集合后,它都不再是强连通的,那么就称S是原图的一个强连通分量(SCC: Strongly Connected Component).任意有向图都可以分解成若干不相交的强连通分量,这就是强连通分量分解.把分解后的强连通分量缩成一个顶点,就得到了一个DAG(有向无环图). 强连通分量分解可以通过

强连通分量分解 tarjan算法 (hdu 1269)

题意: 给出一个有n个点m条边的有向图,判断该图是否只有一个强连通分量. 限制: 0 <= N <= 10000 0 <= M <= 100000 思路: tarjan算法分解强连通分量. /*强连通分量分解 tarjan算法 (hdu 1269) 题意: 给出一个有n个点m条边的有向图,判断该图是否只有一个强连通分量. 限制: 0 <= N <= 10000 0 <= M <= 100000 */ #include<iostream> #inc

强连通分量分解 Kosaraju算法 (poj 2186 Popular Cows)

poj 2186 Popular Cows 题意: 有N头牛, 给出M对关系, 如(1,2)代表1欢迎2, 关系是单向的且可以传递, 即1欢迎2不代表2欢迎1, 但是如果2也欢迎3那么1也欢迎3. 求被所有牛都欢迎的牛的数量. 限制: 1 <= N <= 10000 1 <= M <= 50000 思路: Kosaraju算法, 看缩点后拓扑序的终点有多少头牛, 且要判断是不是所有强连通分量都连向它. Kosaraju算法,分拆完连通分量后,也完成了拓扑序. /*poj 2186

强连通分量分解

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int N = 10000 + 10; const int M = 50000 + 10; int n, m; int head1[N], tot1, head2[N], tot2; bool vis[N

POJ2186(强连通分量分解)

Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 35035   Accepted: 14278 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 &

poj 2186 强连通入门题目

每头牛的梦想就是成为牛群中最受欢迎的牛. 在一群N(1 <= N <= 10,000)母牛中, 你可以得到M(1 <= M <= 50,000)有序的形式对(A,B),告诉你母牛A认为母牛 B很受欢迎. 由于流行是传递性的,如果A认为B很受欢迎,B认为C受欢迎,那么A也会认为C是流行的,即使这不是输入中有序对明确规定的. 你的任务是计算每头奶牛认为受欢迎的奶牛数量. 水题 强连通入门题目. tarjin缩点  然后就变成一棵树, 然后就是求有多少个点的出度为0 输入这个点里面包含的

POJ 3694 强连通分量+LCA

点击打开链接 题意:给一个图,然后依次加进去边,问每次加过边后还有几个桥,之前加入的会影响后面加入的 思路:先将图的桥全部找出来,然后将桥的点标记上,然后不需要缩点,直接进行裸的LCA,再找最近公共祖先的时候,遇到标记的点将结果减1,然后将标记取消,不知道为什么我写的跑的特别慢,别人写的都很快,有神犇知道求指教 #include <vector> #include <stdio.h> #include <stdlib.h> #include <string.h&g

强连通分量tarjan模板复习

对于一个有向图定点的子集,在该子集中任取两点u与v,都能找到一条从u到v的路径,则称该子集是强连通的.若该集合加入到任意点集中,它都不再强连通,则称这个子集是原图的一个强连通分量.任意一张图都可以分解成若干个不相交的强连通分量.这是强连通分量分解.把分解后的强连通分量缩成一个顶点,就可以得到一个有向无环图. 如图: 求一张图的强连通分量的个数,常用tarjan算法,它是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈

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

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