Description
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
Input
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
Output
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
Hint
題目大意:有 N 頭牛,M 對關係(例如 A -> B)構成一個有向圖,關係的含義爲 A -> B 爲牛 A 認爲牛 B Good。關係間具有傳遞性,若有 A -> B 、B -> C,則有 A -> C。問有多少頭牛被所有牛認爲 Good。
強連通分量縮點的經典題目。有向圖可以看成是由若干強連通分量構成的 DAG ,A 認爲 B Good 可以看成 A 可以到 B 。每一個強連通分量內的點均互相可達,則任意與他們中的點的出邊相連的點都是可達的。那麼該 DAG(強連通分量縮點後的圖) 中有且僅有一個出度爲零的點時,該點對任意點而言都是可達的。那麼題目轉化爲求強連通分量縮點後的 DAG 中是否存在唯一的點出度零。若存在,則該連通分量內的點數即爲答案,否則答案爲零。
一開始第二個 DFS 寫挫了,T 了一晚上。。。
貼個代碼以示教訓:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<stack>
#include<cstring>
using namespace std;
const int maxn = 1e4 + 5;
int n,m;
bool vis[maxn];
vector<int> v[maxn];
stack<int> s;
int cnt[maxn],pre[maxn],dev[maxn],out[maxn],sum[maxn];
int dfs_time = 1,cou = 1;
void DFS(int x)
{
int len = v[x].size();
dev[x] = pre[x] = dfs_time++;
s.push(x);
for(int i = 0;i < len; ++i)
{
int u = v[x][i];
if(!vis[u])
{
vis[u] = true;
DFS(u);
dev[x] = min(dev[x],dev[u]);
}
else if(!cnt[u]) dev[x] = min(dev[x],pre[u]);
}
if(pre[x] == dev[x])
{
int temp;
while(!s.empty())
{
temp = s.top();
s.pop();
cnt[temp] = cou;
++sum[cou];
if(temp == x) break;
}
++cou;
}
}
void Solve(int x)
{
int len = v[x].size();
for(int i = 0;i < len; ++i)
{
int u = v[x][i];
if(cnt[x] != cnt[u]) out[cnt[x]]++;
if(!vis[u])
{
vis[u] = true;
Solve(u);
}
}
}
int main()
{
scanf("%d %d",&n,&m);
int x,y;
for(int i = 0;i <= n; ++i)
{
cnt[i] = sum[i] = out[i] = 0;
vis[i] = false;
}
for(int i = 0;i < m; ++i)
{
scanf("%d %d",&x,&y);
v[x].push_back(y);
}
for(int i = 1;i <= n; ++i)
{
if(!vis[i])
{
vis[i] = true;
DFS(i);
}
}
memset(vis,false,sizeof(vis));
for(int i = 1;i <= n; ++i)
{
if(!vis[i])
{
vis[i] = true;
Solve(i);
}
}
int ans = 0,num = 0;
for(int i = 1;i < cou; ++i) if(!out[i]) ++num,ans = sum[i];
printf("%d\n",num == 1 ? ans : 0);
return 0;
}