当前位置: 代码迷 >> 综合 >> 受欢迎的牛——Tarjan
  详细解决方案

受欢迎的牛——Tarjan

热度:21   发布时间:2023-12-22 02:16:59.0

每一头牛的愿望就是变成一头最受欢迎的牛。现在有 头牛,给你 对整数 ,表示牛 认为牛 受欢迎。这种关系是具有传递性的,如果 认为 受欢迎, 认为 受欢迎,那么牛 也认为牛 受欢迎。你的任务是求出有多少头牛被除自己之外的所有牛认为是受欢迎的。

输入格式
第一行两个数 ;
接下来 行,每行两个数 ,意思是 认为 是受欢迎的(给出的信息有可能重复,即有可能出现多个 )。

输出格式
输出被除自己之外的所有牛认为是受欢迎的牛的数量。

样例
输入
3 3
1 2
2 1
2 3
输出
1
只有第三头牛被除自己之外的所有牛认为是受欢迎的。

这道题写了好几天,前几天每天就是只看了半个小时,今天下午下定决心看这个题 终于把题意,算法,各数组弄清楚了

先用tarjan算法处理所有的强连通分量块出来,同时计算每个强连通块中点的个数。然后枚举所以的边,如果一条边的两个结点属于不同的强连通块,那么就把发出这条边的联通块的出度+1,最后寻找是否存在出度为0的强连通块,因为受所有牛的欢迎(在一个强联通块中的牛只要有一个欢迎另一头不再强连通块中的牛,那么强连通块中其他牛就欢迎)所以一定所以的强连通块都有边连向这个强联通块。
sc是强连通块的块数
scc表示不同的强连通块,sz表示强连通块中的点数

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stack>
#define mem(a,b) memset(a,b,sizeof(a))
const int N=2020;
typedef long long ll;
using namespace std;
struct node
{
    int to,net;
} e[N];
int head[N],tot;
void add(int u,int v)
{
    e[++tot].to=v;e[tot].net=head[u];head[u]=tot;
}
int dfn[N],low[N],cnt,s[N],tp;
int scc[N],sc;
int sz[N],n,m,out[N];
void tarjan(int u)
{
    low[u]=dfn[u]=++cnt;s[++tp]=u;for(int i=head[u]; i; i=e[i].net){
    int v=e[i].to;if(!dfn[v]){
    tarjan(v);low[u]=min(low[u],low[v]);}else if(!scc[v])low[u]=min(low[u],low[v]);}if(dfn[u]==low[u]){
    ++sc;while(s[tp]!=u)scc[s[tp]]=sc,sz[sc]++,--tp;scc[s[tp]]=sc,sz[sc]++,--tp;}
}
int main()
{
    scanf("%d%d",&n,&m);for(int i=1; i<=m; i++){
    int u,v;scanf("%d%d",&u,&v);add(u,v);}for(int i=1; i<=n; i++){
    if(!dfn[i])tarjan(i);}for(int u=1; u<=n; u++){
    for(int i=head[u]; i; i=e[i].net){
    int v=e[i].to;if(scc[u]==scc[v])   continue;out[scc[u]]++;}}int ans=0;for(int i=1; i<=sc; i++){
    if(!out[i]){
    if(!ans)  ans=i;else{
    printf("0\n");return 0;}}}printf("%d\n",sz[ans]);return 0;
}