P2002 消息扩散(缩点)

描述:https://www.luogu.com.cn/problem/P2002

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


tarjan缩点

缩点以后图就变成了几张无环图

那么对于这样的图,入度为0的点就是答案

因为入度不为0的点会一直把消息传达下去

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <math.h>
using namespace std;
const int maxn=500005;
int n,m,fen,belong[maxn];
struct p{
    int to,nxt;
}d[maxn];int cnt=1,head[maxn];
void add(int u,int v){
    d[cnt].nxt=head[u],d[cnt].to=v,head[u]=cnt++;
}
int low[maxn],dfn[maxn],stac[maxn],vis[maxn],top,id,ru[maxn];
void tarjan(int x){
    dfn[x]=low[x]=++id;vis[x]=1;
    stac[++top]=x;vis[x]=1;
    for(int i=head[x];i;i=d[i].nxt){
        int y=d[i].to;
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(vis[y])    low[x]=min(low[x],low[y]);
    }
    if(low[x]==dfn[x]){
        fen++;//记录连通分量
        int temp;
        while(temp=stac[top--]) 
        {
            belong[temp]=fen;//记录在哪个连通分量
            vis[temp]=0; 
            if(temp==x)    break;
        }
    }
}
int main()
{
    int n,m;
    cin>>n>>m;
    int x,y;
    for(int i=1;i<=m;i++){
        cin>>x>>y;
        add(x,y);
    }
    for(int i=1;i<=n;i++)
    if(!dfn[i])    tarjan(i);
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=d[j].nxt)
            if(belong[i]!=belong[d[j].to])//处于不同的连通分量
                ru[belong[d[j].to]]++; 
    }
    int ans=0;
    for(int i=1;i<=fen;i++)
    if(!ru[i])    ans++;
    cout<<ans;
    return 0;
}

 

posted @ 2020-03-21 10:09  倾叶子佮  阅读(318)  评论(0编辑  收藏  举报