題意:每頭牛都想成爲牛羣中的紅人。給定N頭牛的牛羣和M個有序對(A, B)。(A, B)表示牛A認爲牛B是紅人。該關係具有傳遞性,所以如果牛A認爲牛B是紅人,牛B認爲牛C是紅人,那麼牛A也認爲牛C是紅人。不過,給定的有序對中可能包含(A, B)和(B, C),但不包含(A,C)。求被其他所有牛認爲是紅人的牛的總數。
比較暴力的思路:假如我們直接暴力就是我們直接建圖,然後再對每個點暴力就可以了,這樣也可以,但是就是時間的問題,肯定會超時的,既然時間上過不去,那麼我們不妨就試試我們剛剛學的強連通分量,
我們直接求出這個圖的拓撲序,想一下,這個點必須是所有的點都可以到達的點,只要我們找那些屬於最後一個分組的點有幾個就行了,然後在走一次dfs看看是不是所有的點都可以到達這個點,這樣我們就把這個題給做出來了,
下面給出AC代碼
#include<bits/stdc++.h>
using namespace std;
#define met(Q,QQ) memset(Q,QQ,sizeof(Q))
const int maxn=1e4+7;
vector<int> G[maxn];//存圖
vector<int> rG[maxn];//把邊反向後的圖
vector<int> vec;//後序遍歷順序的圖
bool vis[maxn];//訪問標記
int cmp[maxn];//所屬強聯通分量的拓撲序列
int n,m;
void add_edge(int from,int to)//存圖
{
G[from].push_back(to);
rG[to].push_back(from);
}
void dfs(int k) //對圖進行dfs,並訪問到的點依次存入vec中,
{
vis[k]=true;
int kk=G[k].size();
for(int i=0;i<kk;i++)
{
int kkk=G[k][i];
if(!vis[kkk]) dfs(kkk);
}
vec.push_back(k);
}
void rdfs(int k,int cnt)//構建拓撲序
{
vis[k]=true;
cmp[k]=cnt;
int kk=rG[k].size();
for(int i=0;i<kk;i++)
{
int kkk=rG[k][i];
if(!vis[kkk]) rdfs(kkk,cnt);
}
}
int main()
{
scanf("%d %d",&n,&m);
int from,to;
for(int i=1;i<=m;i++)
{
scanf("%d %d",&from,&to);
add_edge(from,to);
}
met(vis,0);
for(int i=1;i<=n;i++)
{
if(!vis[i]) dfs(i);
}
met(vis,0);
int kk=vec.size();
int cnt=0;
for(int i=kk-1;i>=0;i--)
{
if(!vis[vec[i]])
{
cnt++;
int qq=vec[i];
rdfs(qq,cnt);
}
}
int sum=0;
int u=0;
for(int i=1;i<=n;i++)
{
if(cmp[i]==cnt)
{
u=i;
sum++;
}
}
met(vis,0);
rdfs(u,0);
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
sum=0;
break;
}
}
printf("%d\n",sum);
return 0;
}