zoukankan      html  css  js  c++  java
  • [Luogu P2341] [HAOI2006]受欢迎的牛 (缩点+bitset)

    题面

    传送门:https://www.luogu.org/problemnew/show/P2341


    Solution

    前排提示,本蒟蒻做法既奇葩又麻烦

    我们先可以把题目转换一下。

    可以把一头牛喜欢另外一头牛理解为另外一头牛被一头牛喜欢。

    我们把被喜欢的关系建边,即B被A喜欢,从B向A连一条有向边

    显然,一个点若能到达其他所有节点,它就是题目中的明星牛。

    接下来,我们可以考虑一个类似于DP的做法。

    一个点能访问到的点,等同于它的儿子们访问的到的点加上它自己

    显然,这种特性要在DAG(有向无环图)上才能方便的使用。

    所以说,我们第一步要对题目做的是缩点。

    缩完点之后,我们就可以进行图上DP了。

    我们可以用一个01数组f[i][j]表示i能具体能到达的点为j(用010101数列表示)。

    显然 f[i] |= f[k] (或运算)(k为i直接相连的点)

    答案为f[i][j] j=11111111.... 的点 

    当然,这样做有一个问题。

    点的最大数目为n,我们这样做是O(n^2)的,在最坏条件(没有一个点能缩在一起)的情况下,会T。

    我们这时候就得请出bitset。

    bitset的食用方法:https://www.cnblogs.com/RabbitHu/p/bitset.html(借用胡小兔dalao的博客)

    使用bitset后,我们计算一个点能到达其他的点的复杂度一下子降为了O(n/32)

    总复杂度为O(n^2/32) 

    然后就可以过啦。


    Code

    //Luogu P2341 [HAOI2006]受欢迎的牛
    //June,5th,2018
    //缩点+(完全没必要的)bitset
    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<stack>
    #include<bitset>
    using namespace std;
    long long read()
    {
        long long x=0,f=1; char c=getchar();
        while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    const int  N=10000+100;
    vector <int> e[N],e2[N];
    int n,m,belong[N],nd_tot,dfn[N],mcount,low[N],cnt[N];
    bool InStack[N];
    stack <int> s;
    bitset <N> arrival[N]; 
    void Tarjan(int now)
    {
        InStack[now]=true;
        s.push(now);
        dfn[now]=low[now]=++mcount;
        for(int i=0;i<int(e[now].size());i++)
            if(dfn[e[now][i]]==0)
            {
                Tarjan(e[now][i]);
                low[now]=min(low[now],low[e[now][i]]);
            }
            else if(InStack[e[now][i]]==true)
                low[now]=min(low[now],low[e[now][i]]);
        if(low[now]==dfn[now])
        {
            nd_tot++;
            while(s.empty()==false)
            {
                int temp=s.top();
                s.pop();
                InStack[temp]=false;
                belong[temp]=nd_tot;
                cnt[nd_tot]++;
                if(temp==now) break;
            }
            arrival[nd_tot][nd_tot]=true;
        }
    }
    bool vis[N];
    int ans=0;
    void dfs(int now)
    {
        vis[now]=true;
        for(int i=0;i<int(e2[now].size());i++)
        {
            if(vis[e2[now][i]]==false)
                dfs(e2[now][i]);
            arrival[now]|=arrival[e2[now][i]];
        }
        if(int(arrival[now].count())==nd_tot)
            ans+=cnt[now];
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++)
            e2[i].reserve(4),
            e[i].reserve(4);
        for(int i=1;i<=m;i++)
        {
            int s=read(),t=read();
            e[t].push_back(s);
        }
        
        for(int i=1;i<=n;i++)
            if(dfn[i]==0)
                Tarjan(i);
        for(int i=1;i<=n;i++)
            for(int j=0;j<int(e[i].size());j++)
                if(belong[i]!=belong[e[i][j]])
                    e2[belong[i]].push_back(belong[e[i][j]]);
        for(int i=1;i<=nd_tot;i++)
            if(vis[i]==false)
                dfs(i);
            
        printf("%d",ans);
        return 0;
    }
    正解(C++)

     

    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    2019 SDN第二次上机作业
    2019 SDN上机第1次作业
    第五次软工作业结对编程
    JIRA中的核心概念
    产品经理与项目经理的区别
    掀起你的盖头来:浅谈项目管理办公室(PMO)
    你大概走了假敏捷:认真说说敏捷的实现和问题(手绘版)
    项目管理经验
    项目经理面试中可能遇到的问题
    回到网易8个月测试团队转型实践
  • 原文地址:https://www.cnblogs.com/GoldenPotato/p/9140872.html
Copyright © 2011-2022 走看看