题目链接:http://poj.org/problem?id=2186
挑战程序设计竞赛P322
题目大意:
每头牛都想成为牛群中的红人。给定N头牛的牛群和M个有序对(A, B)。(A, B)表示牛A认为牛B是红人。该关系具有传递性,所以如果牛A认为牛B是红人,牛B认为牛C是红人,那么牛A也认为牛C是红人。不过,给定的有序对中可能包含(A,B)和(B,C),但不包含(A,C)。求被其他所有牛认为是红人的牛的总数。
分析:
需要掌握Kosaraju求得的强连通分量满足拓扑序,具体解释请看挑战程序设计竞赛。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int max_v = 100005;
int N, M;
int V;
vector<int> G[max_v];
vector<int> rG[max_v];
vector<int> vs;
bool used[max_v];
int cmp[max_v];
void add_edge(int from, int to)
{
G[from].push_back(to);
rG[to].push_back(from);
}
void dfs(int u)
{
used[u] = true;
for(int i = 0; i < G[u].size(); i++)
if(!used[G[u][i]])
dfs(G[u][i]);
vs.push_back(u);
}
void rdfs(int u, int k)
{
used[u] = true;
cmp[u] = k;
for(int i = 0; i < rG[u].size(); i++)
if(!used[rG[u][i]])
rdfs(rG[u][i], k);
}
int src()
{
memset(used, 0, sizeof(used));
vs.clear();
for(int u = 0; u < V; u++)
if(!used[u])
dfs(u);
memset(used, 0, sizeof(used));
int k = 0;
for(int i = vs.size()-1; i >= 0; i--)
if(!used[vs[i]])
rdfs(vs[i], k++);
return k;
}
int main()
{
while(cin >> N >> M)
{
V = N;
for(int i = 0; i <= N-1; i++)
{
if(!G[i].empty())
G[i].clear();
if(!rG[i].empty())
rG[i].clear();
}
for(int i = 0; i < M; i++)
{
int u, v;
cin >> u >> v;
add_edge(u-1, v-1);
}
int n = src();
int u = 0, num = 0;
for(int v = 0; v < V; v++)
if(cmp[v] == n-1)
{
u = v;
num++;
}
memset(used, 0, sizeof(used));
rdfs(u, 0);
for(int v = 0; v < V; v++)
if(!used[v])
{
num = 0;
break;
}
cout << num << endl;
}
return 0;
}