码迷,mamicode.com
首页 > 移动开发 > 详细

【小结】强联通分量分解

时间:2015-07-17 22:48:46      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:

强联通分量

  • 在一个有向图的顶点子集S中,对?(u,v),如果都能找到一条从uv的路径,那么就称S是强联通的。如果向S中加入任何一个其他顶点后S都不再是强联通的,就称S时原图的一个强联通分量。
  • 显然,如果把所有的强联通分量都缩点,原图将变成一个DAG
  • SCC的求解可通过两次dfs实现,第一次在原图中后续遍历,标号;第二遍将所有边反向后,从编号最大的点开始遍历,每次都可得到一个SCC
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAX_V = 1024;
vector<int> G[MAX_V];
vector<int> rG[MAX_V]; //rev-G
vector<int> vs; //node-list while post-visit
bool used[MAX_V]; //flag
int cmp[MAX_V]; //tupper

int V; //node

void addEdge(int from, int to)
{
    G[from].push_back(to);
    rG[to].push_back(from);
}

void dfs(int v)
{
    used[v] = true;
    for (int i = 0; i < G[v].size(); ++i)
    {
        if (!used[G[v][i]])
        {
            dfs(G[v][i]);
        }
    }
    vs.push_back(v);
}

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

int scc()
{
    memset(used, false, sizeof(used));
    vs.clear();
    for (int v = 0; v < V; ++v)
    {
        if (!used[v])
        {
            dfs(v);
        }
    }
    memset(used, false, sizeof(used));
    int k = 0;
    for (int i = vs.size() - 1; i >= 0; --i)
    {
        if (!used[vs[i]])
        {
            rdfs(vs[i], k++);
        }
    }
    return k;
}

int main()
{
    return 0;
}

POJ2186 Popular Cows

  • 问有几只奶牛受欢迎
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAX = 10007;

vector<int> G[MAX];
vector<int> rG[MAX];
stack<int> S;
bool vis[MAX];
int cmp[MAX];
int N, M;

inline void add_edge(int x, int y)
{
    G[x].push_back(y);
    rG[y].push_back(x);
}

void dfs(int v)
{
    vis[v] = true;
    for (int i = 0; i < G[v].size(); ++i)
    {
        if (!vis[G[v][i]])
        {
            dfs(G[v][i]);
        }
    }
    S.push(v);
}

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

int scc()
{
    memset(vis, false, sizeof(vis));
    for (int i = 1; i <= N; ++i)
    {
        if (!vis[i])
        {
            dfs(i);
        }
    }

    int k = 0;
    memset(vis, false, sizeof(vis));
    while (!S.empty())
    {
        int to = S.top();
        S.pop();

        if (!vis[to])
        {
            rdfs(to, ++k);
        }
    }
    return k;
}

void travel(int v)
{
    vis[v] = true;
    for (int i = 0; i < rG[v].size(); ++i)
    {
        if (!vis[rG[v][i]])
        {
            travel(rG[v][i]);
        }
    }
}

int gao()
{
    int cnt = scc();
    /*
        printf("cnt = %d\n", cnt);
        for (int i = 1; i <= N; ++i)
        {
            printf("cmp[%d] = %d\n", i, cmp[i]);
        }
    */
    for (int i = 1; i <= N; ++i)
    {
        if (cmp[i] == cnt)
        {
            memset(vis, false, sizeof(vis));
            travel(i);

            int res = 0;

            for (int j = 1; j <= N; ++j)
            {
                if (!vis[j])
                {
                    return 0;
                }
                if (cmp[j] == cnt)
                {
                    ++res;
                }
            }
            return res;
        }
    }
    return 0;
}

int main()
{
    while (~scanf(" %d %d", &N, &M))
    {
        for (int i = 1; i <= N; ++i)
        {
            G[i].clear();
            rG[i].clear();
        }

        int A, B;
        while (M--)
        {
            scanf(" %d %d", &A, &B);
            add_edge(A, B);
        }

        printf("%d\n", gao());
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

【小结】强联通分量分解

标签:

原文地址:http://blog.csdn.net/bit_line/article/details/46932039

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!