計蒜客習題:受歡迎的蒜頭
阿新 • • 發佈:2019-01-02
問題描述
蒜廠除了蒜頭君還有很多小蒜頭。
每隻蒜頭的夢想是成為最受歡迎的蒜頭。有 N 只蒜頭,有 M 對二元關係 (A,B),告訴你蒜頭 A 認為蒜頭 B 是受歡迎的。如果 A 認為 B 是受歡迎的,B 認為 C 是受歡迎的,則 A 也認為 C 是受歡迎的。你的任務是計算被其餘蒜頭都認為是受歡迎的蒜頭數量。
輸入格式
第一行兩個正整數 N 和 M,分別表示一共有 N 只小蒜頭和 M 對二元關係(1≤N≤10000,1≤M≤50000)。
接下來 M 行,每行兩個整數 A 和 B,表示 A 認為 B 是受歡迎的 (1≤A,B≤N)。
輸出格式
一行一個整數,表示答案。
樣例輸入
4 6
1 2
1 3
1 4
2 3
2 4
3 4
樣例輸出
1
AC程式碼
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
using namespace std;
const int maxn=2e5+10;
vector<int>v[maxn];//鄰接表,存原圖
vector<int>scc[maxn];//縮點後的圖
stack <int>s;
int dfn[maxn],low[maxn],tot,ins[maxn];
//dfn是否為0可以判斷點是否訪問過,ins陣列用來判斷點是否在棧中
//dfn陣列表示頂點dfs的時間戳,low[]為u能夠追溯到的最早的棧中頂點的次序號
int scc_cnt;//強聯通分量的個數
int sccnum[maxn];//縮點陣列,表示某個點對應的縮點值,即縮完點之後的下標
int in[maxn],out[maxn];//出度入度
int n,m;
void readin()//因為初始化問題,莫名其妙的wa,真的醉
{
int x,y;
tot=0;
scc_cnt=0;
fill(ins,ins+maxn,0);
fill(sccnum,sccnum+maxn,0); fill(dfn,dfn+maxn,0);fill(low,low+maxn,0);
fill(in,in+maxn,0);
fill(out,out+maxn,0);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) v[i].clear(),scc[i].clear(); while(!s.empty()) s.pop();
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
v[x].push_back(y);
}
}
void tarjan(int x)
{
low[x]=dfn[x]=++tot;//
s.push(x);ins[x]=1;
for(int i=0;i<v[x].size();i++){
int p=v[x][i];
if(!dfn[p]){//判斷點是否被訪問過
tarjan(p);
low[x]=min(low[x],low[p]);
}
else if(ins[p]) low[x]=min(low[x],dfn[p]);//判斷點是否在棧中
}
if(low[x]==dfn[x]){//dfs到葉子節點,開始判斷,如果==就到達了某個強聯通分量的根節點,dfs回溯到了這個點
scc_cnt++;
scc[scc_cnt].clear();
while(1){//得出某個強聯通分量的集合
int now=s.top();
s.pop();
ins[x]=0;//出棧ins置0
if(sccnum[now]!=scc_cnt) scc[scc_cnt].push_back(x);
sccnum[now]=scc_cnt;//將該連通分量中的每個點都賦予相同的值
if(now==x) break;//通過棧找到那個點
}
}
}
int main()
{
readin();
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i);
}
}
//出度入度的統計方法
for(int u=1;u<=n;u++){
for(int i=0;i<v[u].size();i++){
int uu=v[u][i];
if(sccnum[u]!=sccnum[uu]){
in[sccnum[uu]]++;
out[sccnum[u]]++;
}
}
}
int ansp=-1;
int flag=-1;
for(int i=1;i<=scc_cnt;i++){
if(out[i]==0){
flag++;
ansp=i;
}
}
if(flag==0) cout<<scc[ansp].size()<<endl;
else cout<<"0"<<endl;
}