zoukankan      html  css  js  c++  java
  • poj2186

    poj2186

    题意

    A -> B表示 A 认为 B是红人,且如果 B -> C,则 A -> C。问有几头牛被所有牛都认为是红人。

    分析

    如果A被所有牛认为是红人,那么A所在的强连通分量里的牛也被所有牛认为是红人。
    至多只有一个强连通分量满足满足题目的条件。(否则这两个强连通分量合并,仍然是一个强连通分量)
    按照Kosaraju算法 求强连通分量时,能够得到各个强连通分量拓扑排序后的顺序,而唯一能成为解的只有拓扑排序最后的连通分量,
    (如果存在这样的强连通分量,那么一定会在第一个DFS中就找到(所有牛都认为它是红人),而由于rDFS逆序遍历,所以编号最大的就是那个强连通分量了。)

    code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include<queue>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    const int MAXN = 1e4 + 10;
    int n, m; // 点、边
    int vis[MAXN];
    int flag[MAXN]; // 所属强连通分量的拓扑序
    vector<int> G[MAXN], rG[MAXN];
    vector<int> vs; // 后序遍历顺序的顶点列表
    
    void addedge(int x, int y)
    {
        G[x].push_back(y);  // 正向图
        rG[y].push_back(x); // 反向图
    }
    
    void dfs(int u)
    {
        vis[u] = 1;
        for(int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if(!vis[v]) dfs(v);
        }
        vs.push_back(u);
    }
    
    void rdfs(int u, int k)
    {
        vis[u] = 1;
        flag[u] = k;
        for(int i = 0; i < rG[u].size(); i++)
        {
            int v = rG[u][i];
            if(!vis[v]) rdfs(v, k);
        }
    }
    
    int scc() // 强连通分量的个数
    {
        vs.clear();
        memset(vis, 0, sizeof vis);
        for(int i = 1; i <= n; i++) // [1...n]
            if(!vis[i]) dfs(i);
        memset(vis, 0, sizeof vis);
        int k = 0;
        for(int i = vs.size() - 1; i >= 0; i--)
            if(!vis[vs[i]]) rdfs(vs[i], k++);
        return k;
    }
    
    int solve()
    {
        int cnt = scc(), num = 0, u = 0;
        for(int i = 1; i <= n; i++)
            if(flag[i] == cnt - 1)
            {
                num++;
                u = i;
            }
        memset(vis, 0, sizeof vis);
        rdfs(u, 0);
        for(int i = 1; i <= n; i++)
            if(!vis[i]) num = 0;
        return num;
    }
    
    int main()
    {
        while(~scanf("%d%d", &n, &m))
        {
            for(int i = 0; i <= n; i++)
            {
                G[i].clear();
                rG[i].clear();
            }
            for(int i = 0; i < m; i++)
            {
                int x, y;
                scanf("%d%d", &x, &y);
                addedge(x, y);
            }
            printf("%d
    ", solve());
        }
        return 0;
    }
    
  • 相关阅读:
    Merge into使用详解( 同时执行inserts和updates操作 )
    sql执行计划解析案例(二)
    包的定义和导入-----package
    jQuery练习实例(四)
    打印沙漏形
    Java的RandomAccessFile
    农场有头大母牛,每年生头小母牛,小母牛五年后生小母牛,问20年后农场一共有多少头牛?(用面向对象的思想)
    关于编译Lambda时报告返回的为void的错误
    银行对账
    mysql查询随机几条数据(速度快)
  • 原文地址:https://www.cnblogs.com/ftae/p/6791260.html
Copyright © 2011-2022 走看看