pku2186

/*
 * File:   pku2186.cpp
 * Author: chenjiang
 *pku2186强联通分量的应用,题意:n头牛,m中关系,
 * 每种关系包括a b ,表示a认为b流行,要求图中被其他
 * 所有牛都认为流行的牛的头数
 * 思路:求图中强联通分量,并求每个强联通分量的出度,若
 * 只有一个强联通分量的出度为0,则这个强联通分量里点的个数
 * 即为所求。当出度为0的强联通分量大于1时,不存在这样的牛。
 * Created on 2010年4月1日, 下午7:59
 */

#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;
#define Max_V 10005
vector<int> v2[Max_V]; //逆图
vector<int> v1[Max_V]; //原图
int n, m; //点数   边数
int ind; //第一次深搜的序号 如:oder[++ind]=u;
int oder[Max_V]; //第一次dfs得出的序列
int Scc_num[Max_V]; //强联通图中点的个数
int Scc_out[Max_V]; //强联通图的出度
int Scc_ID[Max_V]; //强联通图的序号
int id;
bool visited[Max_V]; //标记是否访问过

void DFS1(int u)//深搜原图
{
    visited[u] = 1;
    for (int i = 0; i < v1[u].size(); i++)//访问u的邻接点
    {
        if (!visited[v1[u][i]])//点v1[u][i]没有被访问过
            DFS1(v1[u][i]); //深搜v1[u][i]的邻接点
    }
    oder[++ind] = u; //记下访问序列
}

void DFS2(int u)//深搜逆图
{
    visited[u] = 1;
    Scc_ID[u] = id;
    Scc_num[id]++;
    for (int i = 0; i < v2[u].size(); i++) {
        if (!visited[v2[u][i]])
            DFS2(v2[u][i]);
    }
}

void kosaroju() {
    int i, j;
    ind = 0;
    memset(visited, 0, sizeof (visited)); //visited[]初始化
    for (i = 1; i <= n; i++)//第一次深搜的过程
    {
        if (!visited[i])
            DFS1(i);
    }

    memset(visited, 0, sizeof (visited));
    memset(Scc_num, 0, sizeof (Scc_num)); //强联通分量的点的个数初始化为0
    id = 0;
    for (i = ind; i >= 1; i--) {//第二次深搜
        if (!visited[oder[i]])
            id++, DFS2(oder[i]);
    }
}

/*
 *
 */
int main(int argc, char** argv) {

    int i, j, a, b;
    //freopen("a.in", "r", stdin);
    while (cin >> n >> m) {
        for (i = 1; i <= n; i++) {
            v1[i].clear();
            v2[i].clear();
        }
        for (i = 1; i <= m; i++) {
            cin >> a >> b;
            v1[a].push_back(b); //原图
            v2[b].push_back(a); //逆图
        }
        kosaroju();

        memset(Scc_out, 0, sizeof (Scc_out));
        for (i = 1; i <= n; i++) {
            for (j = 0; j < v1[i].size(); j++) {
                if (Scc_ID[i] != Scc_ID[v1[i][j]]) {
                    Scc_out[Scc_ID[i]]++;
                }
            }
        }
        int ans, num;
        num = 0;
        for (i = 1; i <= id; i++) {
            if (Scc_out[i] == 0) {
                ans = i;
                num++;
            }
        }
        if (num > 1)
            cout << "0" << endl;
        else
            cout << Scc_num[ans] << endl;
    }
    return (EXIT_SUCCESS);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值