luogu P2002 消息擴散
阿新 • • 發佈:2017-06-24
++ 連接 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> usingnamespace 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]; voidadd_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 消息擴散