首页 > 代码库 > luogu P2002 消息扩散
luogu P2002 消息扩散
题目背景
本场比赛第一题,给个简单的吧,这 100 分先拿着。
题目描述
有n个城市,中间有单向道路连接,消息会沿着道路扩散,现在给出n个城市及其之间的道路,问至少需要在几个城市发布消息才能让这所有n个城市都得到消息。
输入输出格式
输入格式:
第一行两个整数n,m表示n个城市,m条单向道路。
以下m行,每行两个整数b,e表示有一条从b到e的道路,道路可以重复或存在自环。
输出格式:
一行一个整数,表示至少要在几个城市中发布消息。
输入输出样例
输入样例#1:
5 41 22 12 35 1
输出样例#1:
2
说明
【数据范围】
对于20%的数据,n≤200;
对于40%的数据,n≤2,000;
对于100%的数据,n≤100,000,m≤500,000.
【限制】
时间限制:1s,内存限制:256M
【注释】
样例中在4,5号城市中发布消息。
tarjan算法将每个强连通分量缩成点,记录原先的每个点缩入了哪个点
缩完之后,扫描每条边,判断如果终点和起点所在的分量不同,标记终点
最后扫描为标记的的点计数器++也就是(入度为0的点)
#include <cstdio>#include <cstring>#include <iostream>using namespace std;int n,m,topp;#define N 100006struct sta{ int sz[100001]; int top(){return sz[topp];} void push(int x){sz[++topp]=x;} void pop(){if(topp>0)topp--;}}stack;struct node{ int v,next;}edge[N*5];int head[N],num;int dfn[N],low[N],color[N];bool vis[N];void add_edge(int x,int y){ edge[++num].v=y;edge[num].next=head[x];head[x]=num;}int cnt;void tarjan(int x){ dfn[x]=low[x]=++num; stack.push(x); vis[x]=1; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].v; if(!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if(vis[v])low[x]=min(low[x],dfn[v]); } if(dfn[x]==low[x]) { ++cnt; int r; do{ r=stack.top(); color[r]=cnt; vis[r]=0; stack.pop(); }while(r!=x); } return ;}int main(){ scanf("%d%d",&n,&m); int a,b; for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b);add_edge(a,b); } num=0; for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); memset(vis,0,sizeof vis); for(int i=1;i<=n;i++) { for(int j=head[i];j;j=edge[j].next) { int v=edge[j].v; if(color[i]!=color[v]) { vis[color[v]]=1; } } } int ans=0; for(int i=1;i<=cnt;i++) if(!vis[i]) ans++; printf("%d\n",ans); return 0;}
luogu P2002 消息扩散
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。