受歡迎的牛——Tarjan
阿新 • • 發佈:2019-02-04
每一頭牛的願望就是變成一頭最受歡迎的牛。現在有 N 頭牛,給你 M 對整數(A,B),表示牛A認為牛B受歡迎。這種關係是具有傳遞性的,如果 A 認為 B 受歡迎,B 認為 C 受歡迎,那麼牛A也認為牛C受歡迎。你的任務是求出有多少頭牛被所有的牛認為是受歡迎的。
輸入格式:
第一行兩個數 N,M 。
接下來 M 行,每行兩個數 A,B,意思是 A 認為 B 是受歡迎的(給出的資訊有可能重複,即有可能出現多個 A,B)
輸出格式:
輸出一個整數,即有多少頭牛被所有的牛認為是受歡迎的。如果沒有滿足這種條件的情況,輸出“0”。
樣例輸入:
3 3
1 2
2 1
2 3
樣例輸出:
1
樣例說明:
只有牛 3 是受到所有牛歡迎的。
資料範圍:
10% 的資料:N≤20;M≤50
30% 的資料:N≤1000;M≤20000
70% 的資料:N≤5000;M≤50000
100% 的資料:N≤10000;M≤50000
題目分析:
Tarjan模板題。只需縮點後記錄出度,當且僅當只有一個出度為0的點(實際可能是一個強連通分量),存在最受歡迎的牛,個數為強連通分量的大小。否則,沒有最受歡迎的牛,輸出0。
注:不懂Tarjan的可以看我的講解:http://blog.csdn.net/qianguch/article/details/54710272
附程式碼:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<iomanip>
#include<cctype>
#include<set>
#include<map>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e4+10;
const int maxm=5e4+10;
int top,tot,n,m,times,cnt,dfn[maxn],low[maxn];
int nxt[maxm],to[maxm],first[maxn],stack[maxn];
int pd[maxn],num[maxn],x,y,du[maxn],sum,bh;
bool vis[maxn],insta[maxn];
void create(int x,int y)
{
tot++;
nxt[tot]=first[x];
first[x]=tot;
to[tot]=y;
}
void dfs(int u)
{
times++;
dfn[u]=times;
low[u]=times;
vis[u]=true;
insta[u]=true;
stack[top++]=u;
for(int e=first[u];e;e=nxt[e])
{
if(vis[to[e]]==false)
{
dfs(to[e]);
low[u]=min(low[u],low[to[e]]);
}
else
if(insta[to[e]]==true)
low[u]=min(low[u],dfn[to[e]]);
}
if(low[u]==dfn[u])
{
cnt++;
while(top>=1&&stack[top]!=u)
{
top--;
insta[stack[top]]=false;
pd[stack[top]]=cnt;
num[cnt]++;//記錄每個強連通分量的大小
}
}
}
int main()
{
//freopen("lx.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
create(x,y);
}
for(int i=1;i<=n;i++)
if(vis[i]==false)
dfs(i);
for(int i=1;i<=n;i++)
for(int e=first[i];e;e=nxt[e])
if(pd[i]!=pd[to[e]])
du[pd[i]]++;//計算出度
for(int i=1;i<=cnt;i++)
{
if(du[i]==0)//看有多少個出度為0
{
sum++;
bh=i;
}
}
if(sum==1)
printf("%d",num[bh]);
else
printf("0");
return 0;
}