链接:https://ac.nowcoder.com/acm/problem/19960
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。
这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。
你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
输入描述:
第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)
输出描述:
一个数,即有多少头牛被所有的牛认为是受欢迎的。
示例1
输入
3 3 1 2 2 1 2 3
输出
1
思路:tarjan求强连通分量,要对属于不同分量的边进行标记。
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
const int N = 100000 + 10;
int n,m;
vector<int> v[N];
int dfn[N],low[N];
int tim;
stack<int> s;
int ans[N];
int cnt;
int vis[N];
int in[N];
vector<int> fina;
int size[N];
int c[N],d[N];
void tarjan(int x)
{
dfn[x] = low[x] = ++tim;
s.push(x);
for(int i=0; i<v[x].size(); i++)
{
int y = v[x][i];
if(!dfn[y])
{
tarjan(y);
low[x] = min(low[x], low[y]);
}
else if(!vis[y])//已确定环的不再遍历
low[x] = min(low[x], dfn[y]);
}
if(dfn[x] == low[x])
{
cnt++;
int a;
do
{
a = s.top();
s.pop();
vis[a] = cnt;
size[cnt]++;
}while(a != x);
}
}
int main()
{
cin>>n>>m;
for(int i=0; i<m; i++)
{
int x,y;
cin>>x>>y;
c[i] = x;
d[i] = y;
v[x].push_back(y);
}
for(int i=1; i<=n; i++)
{
if(!dfn[i]) tarjan(i);
}
for(int i=0; i<m; i++)
{
if(vis[c[i]] != vis[d[i]])//两个环可以联通,删掉其中一个的vis值
{
in[vis[c[i]]]++;
}
}
int total = 0;
for(int i=1; i<=cnt; i++)
{
if(!in[i])
{
if(total)
{
puts("-1");
return 0;
}
total = i;
}
}
cout<<size[total];
return 0;
}