洛谷 2002_消息扩散_强连通分量

发布于 2019-05-23  908 次阅读


题目描述

有n个城市,中间有单向道路连接,消息会沿着道路扩散,现在给出n个城市及其之间的道路,问至少需要在几个城市发布消息才能让这所有n个城市都得到消息。


思路

用tarjian求强连通分量,输出入度为0的个数即可


#include 
#include 
#include 
#include 
using namespace std;
#define maxn 600000
#define fill(x, y) memset(x, y, sizeof(x))
struct edge
{
    int from, to, next;
}e[maxn];
int ls[maxn], f[maxn], n, m, dfn[maxn], low[maxn], bcnt = 0, instack[maxn], dindex = 0, belong[maxn], in[maxn];
stack s;
void tarjan(int now)
{
    dindex++;
    dfn[now] = dindex;
    low[now] = dindex;
    s.push(now);
    instack[now] = 1;
    for (int i = ls[now]; i; i = e[i].next)
    {
        if (dfn[e[i].to] == 0)
        {
            tarjan(e[i].to);
            if (low[now] > low[e[i].to]) low[now] = low[e[i].to];
        }
        else
        {
            if (instack[e[i].to] && dfn[e[i].to] < low[now])
                low[now] = dfn[e[i].to];
        }
    }
    if (dfn[now] == low[now])
    {
        bcnt++;
        int j;
        do
        {
            j = s.top();
            s.pop();
            instack[j] = 0;
            belong[j] = bcnt;
        }
        while(now != j);
    }
}
void work()
{
    for (int i = 1; i <= n; i++)
        if (dfn[i] == 0) tarjan(i);
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        e[i] = (edge) {x, y, ls[x]};
        ls[x] = i;
    }
    work();
    for (int i = 1; i <= m; i++)
        if (belong[e[i].from] != belong[e[i].to])
            in[belong[e[i].to]]++;
    int ans = 0;
    for (int i = 1; i <= bcnt; i++)
        if (in[i] == 0) ans++;
    printf("%d\n", ans);
}
]]>