1. 程式人生 > >luogu P2002 消息擴散

luogu P2002 消息擴散

++ 連接 set sin scanf opp push col esp

題目背景

本場比賽第一題,給個簡單的吧,這 100 分先拿著。

題目描述

有n個城市,中間有單向道路連接,消息會沿著道路擴散,現在給出n個城市及其之間的道路,問至少需要在幾個城市發布消息才能讓這所有n個城市都得到消息。

輸入輸出格式

輸入格式:

第一行兩個整數n,m表示n個城市,m條單向道路。

以下m行,每行兩個整數b,e表示有一條從b到e的道路,道路可以重復或存在自環。

輸出格式:

一行一個整數,表示至少要在幾個城市中發布消息。

輸入輸出樣例

輸入樣例#1:
5 4
1 2
2 1
2 3
5 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 100006 struct 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 消息擴散