Popular Cows
Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
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.
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.
* Line 1: Two space-separated integers, N and M
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
* Line 1: A single integer that is the number of cows who are considered popular by every other cow.
3 3 1 2 2 1 2 3
1
Cow 3 is the only cow of high popularity.
题意:如果A认为B牛逼,B认为C牛逼,A也认为C牛逼(有向图),求有被所有牛都认为牛逼的牛的个数
用到强连通分量的模板,但不是单纯的求强连通分量
思路:
假设两头牛A和B都被其他所有牛人认为牛逼,所以A,B互相认为和牛逼,AB属于一个强连通分量,所以如果我们找到一个符合的强连通分量,那么这里面的所有点都牛逼
既然要被其他所有点都认为牛逼,那么应该选择强连通分量分解后拓扑序的最后一个强连通分量,但是还不一定正确,还要判断这强连通分量中的一点(只需要判断一点就可以了,因为强连通嘛)是否可以到达其他所有点,可以就输出这个强连通分量中点个数,否则为0
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
vector<int>G[10009],VG[10009];
vector<int>v;
int vis[10009];
int cmp[10009];
int n,m;
void dfs(int u){
int i;
vis[u] = 1;
for(i = 0; i < G[u].size(); i++){
if(!vis[G[u][i]])
dfs(G[u][i]);
}
v.push_back(u);
}
void redfs(int u,int k){
int i;
vis[u] = 1;
cmp[u] = k;//求强连通分量的同时求出了每个分量的拓扑序
for(i = 0; i < VG[u].size(); i++){
if(!vis[VG[u][i]]){
redfs(VG[u][i],k);
}
}
}
int scc(){
int i;
memset(vis,0,sizeof(vis));
for(i = 1; i <= n; i++){
if(!vis[i])
dfs(i);
}
int cnt = 0;
int k;//记录强连通分量的拓扑序
memset(vis,0,sizeof(vis));
for(i = v.size()-1; i >= 0; i--){
if(!vis[v[i]]){
redfs(v[i],k++);
}
}
return k;
}
void solve(){
int cnt = scc();//进行强连通分量的分解,同事求出分量的拓扑序
int i;
int num = 0;
int u = 0;
for(i = 1; i <= n; i++){
if(cmp[i] == cnt-1){//寻找拓扑序最后的分量,统计个数,记录其中的一个点
u = i;
num++;
}
}
memset(vis,0,sizeof(vis));
redfs(u,0);//从这个记录的点反向进行遍历如果是可以的,一定可以行遍所有的点
for(i = 1; i <= n; i++){
if(!vis[i]){//因此一旦发现还有没遍历的点,说明一定是错误的输出0
num = 0;
break;
}
}
cout << num << endl;
}
int main(){
cin >> n >> m;
int i;
for(i = 1; i <= m; i++){
int u,v;
cin >> u >> v;
G[u].push_back(v);
VG[v].push_back(u);
}//读入
solve();//求解
return 0;
}