受欢迎的蒜头 计蒜客

问题描述

受欢迎的蒜头

思路

tarjan算法 + 缩点
先把一个图的各个强连通分量求出(使用tarjan算法),接着用缩点的形式构建一个有向无环图(把各个强连通分量看成一个点,利用点与点之间的关系,构建一个强连通分量之间的有向图,而且这个图一定是无环的图)
然后分析这个有向无环图的出入度情况,出度为0,入度不为0,那这个强连通分量里的点是可能被所有的点到达的

ac代码

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

const int MAX_N=10001;
const int MAX_M=50001;
struct edge{
    int u,v,next;
    edge(){}
    edge(int _u,int _v,int _n):u(_u),v(_v),next(_n){}
}e[MAX_M];
int p[MAX_N];
int belong[MAX_N],scc=0;//统计各个点属于那个连通分量,连通分量数
int idx=0;//时间戳
int dfn[MAX_N],low[MAX_N];//dfn[i]表示点i被tarjan访问的时间,low[i]表示i及i的子树在栈中出现的最早的时间。
int s[MAX_N],top=0;//模拟栈
bool in_stack[MAX_N];//标记是否在栈中
int in[MAX_N],out[MAX_N];//统计缩点之后的有向无环图图的出入度情况

void tarjan(int u){
        dfn[u]=low[u]=++idx;//先记录改点的时间戳
        s[top++]=u;//放入栈中
        in_stack[u]=true;//标记已放入栈中
        for(int i=p[u];i+1;i=e[i].next){//遍历u指向的邻边
            int v=e[i].v;
            if(!dfn[v]){
                tarjan(v);
                low[u]=min(low[u],low[v]);//回溯之后更新low[u]为点u及u点子树的在栈中出现最早的时间
            }
            else if(in_stack[v]){
                low[u]=min(low[u],dfn[v]);//成环,将low[u]更新成最早出现的时间
            }
        }
        if(dfn[u]==low[u]){//是根
            scc++;
            do{
                belong[s[--top]]=scc;//标记为第scc号连通分量的点
                in_stack[s[top]]=false;//出栈标记
            }while(s[top]!=u);
        }
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    memset(p,-1,sizeof(p));
    for(int i=0;i<m;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        e[i]=edge(u,v,p[u]);
        p[u]=i;
    }
    memset(dfn,0,sizeof(dfn));
    memset(in_stack,false,sizeof(in_stack));
    for(int i=1;i<=n;++i){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    if(scc==1){printf("%d\n",n);return 0;}//就一个强连通分量,那任意两个点都是可以互相到达的
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    for(int i=0;i<m;++i){//缩点
        int u=e[i].u;
        int v=e[i].v;
        if(belong[u]!=belong[v]){//统计个点的出入度情况
            out[belong[u]]++;
            in[belong[v]]++;
        }
    }
    int std_scc=0;
    for(int i=1;i<=scc;++i){
        if(in[i]>0&&out[i]==0){//存在两个 “不能到达其他地方的点,只能由其它点到达的点” ,那任何点都不可能被其他所有点到达
            if(std_scc){
                printf("0\n");
                return 0;
            }
            std_scc=i;
        }
    }
    int sum=0;
    for(int j=1;j<=n;++j){
        if(belong[j]==std_scc)
            sum++;
    }
    printf("%d\n",sum);
    return 0;//give me five
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值