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;
    }
    
  • 相关阅读:
    zoj 3627#模拟#枚举
    Codeforces 432D Prefixes and Suffixes kmp
    hdu 4778 Gems Fight! 状压dp
    CodeForces 379D 暴力 枚举
    HDU 4022 stl multiset
    手动转一下田神的2048
    【ZOJ】3785 What day is that day? ——KMP 暴力打表找规律
    poj 3254 状压dp
    C++中运算符的优先级
    内存中的数据对齐
  • 原文地址:https://www.cnblogs.com/ftae/p/6791260.html
Copyright © 2011-2022 走看看