zoukankan      html  css  js  c++  java
  • Tarjan模板题——牛的舞会

    题目描述

    约翰的N (2 <= N <= 10,000)只奶牛非常兴奋,因为这是舞会之夜!她们穿上礼服和新鞋子,别 上鲜花,她们要表演圆舞.

    只有奶牛才能表演这种圆舞.圆舞需要一些绳索和一个圆形的水池.奶牛们围在池边站好, 顺时针顺序由1到N编号.每只奶牛都面对水池,这样她就能看到其他的每一只奶牛.

    为了跳这种圆舞,她们找了 M(2<M< 50000)条绳索.若干只奶牛的蹄上握着绳索的一端, 绳索沿顺时针方绕过水池,另一端则捆在另一些奶牛身上.这样,一些奶牛就可以牵引另一些奶 牛.有的奶牛可能握有很多绳索,也有的奶牛可能一条绳索都没有.

    对于一只奶牛,比如说贝茜,她的圆舞跳得是否成功,可以这样检验:沿着她牵引的绳索, 找到她牵引的奶牛,再沿着这只奶牛牵引的绳索,又找到一只被牵引的奶牛,如此下去,若最终 能回到贝茜,则她的圆舞跳得成功,因为这一个环上的奶牛可以逆时针牵引而跳起旋转的圆舞. 如果这样的检验无法完成,那她的圆舞是不成功的.

    如果两只成功跳圆舞的奶牛有绳索相连,那她们可以同属一个组合.

    给出每一条绳索的描述,请找出,成功跳了圆舞的奶牛有多少个组合?

    输入输出格式

    输入格式:

    Line 1: Two space-separated integers: N and M

    Lines 2..M+1: Each line contains two space-separated integers A and B that describe a rope from cow A to cow B in the clockwise direction.

    输出格式:

    Line 1: A single line with a single integer that is the number of groups successfully dancing the Round Dance.

    输入输出样例

    输入:

    5 4
    2 4
    3 5
    1 2
    4 1

    输出:

    1

    这道题思路还是很简单的 一个裸的tarjan强连通分量 在这里还是着重解释一下tarjan,代码如下:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 100010
    int n,m;
    int cnt;//记录强连通分量的个数 
    int vis_num;//遍历的步数 
    int dfn[maxn];//记录元素第一次被访问的步数
    int low[maxn];//包含i的强连通分量最早被访问的步数
    int num[maxn];//记录强连通分量里的点的个数
    int belong[maxn];//i从属的强连通分量
    int top;//栈中元素的个数
    int stack[maxn];//手打栈
    int instack[maxn];//判断元素是否在栈中
    int head[maxn];
    struct node//链式前向星存边 
    {
        int to,nex;
    }edge[maxn];
    inline int read()//读入优化 
    {
        char kr=0;
        char ls;
        for(;ls>'9'||ls<'0';kr=ls,ls=getchar());
        int xs=0;
        for(;ls>='0'&&ls<='9';ls=getchar())
        {
            xs=xs*10+ls-48;
        }
        if(kr=='-') xs=0-xs;
        return xs;
    }
    void tarjan(int);
    int main()
    {
        int ans=0;
        int p,q;
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            p=read();q=read();
            edge[i].to=q;
            edge[i].nex=head[p];
            head[p]=i;
        }
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])//i没被访问过了
            {
                tarjan(i);
            } 
        }
        for(int i=1;i<=cnt;i++)
        {
            if(num[i]>1)
            {
                ans++;
            }
        }
        printf("%d
    ",ans);
    return 0; 
    }
    void tarjan(int u)
    {
        int v;
        vis_num++;
        dfn[u]=low[u]=vis_num;
        stack[++top]=u;//入栈
        instack[u]=1;//入栈
        for(int i=head[u];i;i=edge[i].nex)
        {
            v=edge[i].to;//下一个访问的点 
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);//判断u是否为v的子节点 
            }
            else if(instack[v])
            {
                low[u]=min(low[u],dfn[v]);
            }
        }
        if(dfn[u]==low[u])//u为强连通分量的根
        {
            cnt++;//强连通分量的个数+1
            do//退栈 
            {
                num[cnt]++;
                v=stack[top--];
                belong[v]=cnt;
                instack[v]=0;
            }while(u!=v);
        }
    }

    这里的belong数组似乎没有什么用,但很多tarjan题目里需要用到belong,这里讲解tarjan代码就放了上来。

    注释里有说的,编号i所属的强连通分量编号,但对于此题没有用

    belong[100010];//i从属的强联通分量的序号


  • 相关阅读:
    全球疫情实时监控——约翰斯&#183;霍普金斯大学数据大屏实现方案
    少儿编程崛起?2020年4月编程语言排名发布——Java,C,Python分列前三,Scratch挤进前20
    干货来了!阿里发布近300页Flink实战电子书
    Druid 0.17 入门(3)—— 数据接入指南
    Druid 0.17 入门(2)—— 安装与部署
    Flink 1.10 正式发布!——与Blink集成完成,集成Hive,K8S
    Druid入门(1)—— 快速入门实时分析利器-Druid_0.17
    程序员需要了解依赖冲突的原因以及解决方案
    每日一技|活锁,也许你需要了解一下
    Dubbo 服务 IP 注册错误踩坑经历
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9562668.html
Copyright © 2011-2022 走看看