题目背景
本题测试数据已修复。
题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶
牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜
欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你
算出有多少头奶牛可以当明星。
输入输出格式
输入格式:
第一行:两个用空格分开的整数:N和M
第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B
输出格式:
第一行:单独一个整数,表示明星奶牛的数量
输入输出样例
输入样例#1:
3 3
1 2
2 1
2 3
输出样例#1:
1
说明
只有 3 号奶牛可以做明星
【数据范围】
10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000
解题思路
如果喜欢一个强连通分量里的任意一只牛,那就是喜欢里面的所有牛,如果强连通分量里的任意一只牛喜欢令一只牛,那么强连通分量里的所有牛都喜欢那只牛,所以可以把一个强连通分量视为一个点,把所有强连通分量都视为一个点之后,图中就不再存在环。当存在且只存在一个出度为0的强连通分量时,那个强连通分量中的所有牛就是明星牛。假设一个强连通分量里的牛是明星牛,就说明他们被所有牛喜欢,如果他们也喜欢其他的牛,那么就有环,而此时图中是不存在环的,所以不可能。如果存在多个出度为0的强连通分量,分量中的牛不喜欢其他的牛,那就不会有牛被所有牛喜欢了。
代码如下
#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <stack>
#include <cmath>
#define maxn 10005
using namespace std;
vector<int> g[maxn];
bool vis[maxn];
int dfn[maxn], low[maxn];
int unit[maxn];
stack<int> sta;
int id;
int cnt;
int ans;
bool tarjan(int x)
{
id ++;
dfn[x] = low[x] = id;
sta.push(x);
vis[x] = true;
for(int i = 0; i < g[x].size(); i ++){
int y = g[x][i];
if(!dfn[y]){
if(!tarjan(y))
return false;
low[x] = min(low[x], low[y]);
}
else if(vis[y])
low[x] = min(low[x], dfn[y]);
}
if(dfn[x] == low[x]){
queue<int> que;
cnt ++;
while(!sta.empty()){
int top = sta.top();
sta.pop();
vis[top] = false;
unit[top] = cnt; //记录这些牛属于哪个强连通分量
que.push(top); //存此分量中的元素
if(top == x)
break;
}
bool flg = true;
int temp = que.size();
while(!que.empty()){ //判断此强连通分量的出度是否为0
int top = que.front();
que.pop();
for(int i = 0; i < g[top].size(); i ++){
int r = g[top][i];
if(unit[r] != unit[top]){ //判断是不是属于同一个强连通分量
flg = false;
break;
}
}
}
if(flg){ //如果这个强连通分量出度为0
if(!ans) //第一个出度为0的
ans = temp; //存个数
else { //如果不止一个
ans = 0; //那么没有明星奶牛
return false; //结束递归
}
}
}
return true;
}
int main()
{
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i ++)
g[0].push_back(i);
for(int i = 0; i < m; i ++){
int a, b;
cin >> a >> b;
g[a].push_back(b);
}
id = 0;
cnt = 0;
ans = 0;
memset(vis, 0, sizeof(vis));
memset(dfn, 0, sizeof(dfn));
memset(unit, 0, sizeof(unit));
tarjan(0);
cout << ans << endl;
return 0;
}