洛谷2002 消息扩散

题目描述

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

输入格式:

第一行两个整数n,m表示n个城市,m条单向道路。

以下m行,每行两个整数b,e表示有一条从b到e的道路,道路可以重复或存在自环。

输出格式:

一行一个整数,表示至少要在几个城市中发布消息。

tarjan缩点以后求出入度为0的点就可以了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100005
#define maxm 500005
using namespace std;
int n,m,cnt,head[maxn],x[maxm],y[maxm],du[maxn];
int dfn[maxn],low[maxn],vis[maxn],bel[maxn],q[maxn];
struct edge{
    int next,to;
}e[maxm];
void insert(int u,int v){
    cnt++;
    e[cnt].next=head[u];e[cnt].to=v;
    head[u]=cnt;
}
int top,ind,k;
void tarjan(int x){
    q[++top]=x;
    dfn[x]=low[x]=++ind;
    vis[x]=1;
    for(int i=head[x];i;i=e[i].next){
        int s=e[i].to;
        if(!dfn[s]){
            tarjan(s);
            low[x]=min(low[s],low[x]);
        }
        else if(vis[s]){
            low[x]=min(dfn[s],low[x]);
        }
    }
    int now=0;
    if(dfn[x]==low[x]){
        k++;
        while(now!=x){
            now=q[top];top--;
            vis[now]=0;
            bel[now]=k;
        }
    }
}
int ans;
void work(){
    for(int i=1;i<=k;i++){
        if(!du[i]){
            ans++;
        }
    }
}
int mx=0;
int main(){
    scanf("%d%d",&n,&m);
    int u,v,t;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x[i],&y[i]);
        insert(x[i],y[i]);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i])tarjan(i);
    }
    cnt=0;
    memset(head,0,sizeof head);
    memset(e,0,sizeof e);
    for(int i=1;i<=m;i++){
        if(bel[x[i]]!=bel[y[i]]){
        insert(bel[x[i]],bel[y[i]]);
        du[bel[y[i]]]++;
        }
    } 
    work();
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Elfish/p/8039526.html