zoukankan      html  css  js  c++  java
  • 【BZOJ4484】最小表示(JSOI2015)-贪心+拓扑排序+bitset

    测试地址:最小表示
    做法:本题需要用到贪心+拓扑排序+bitset。
    显然,如果一条边对连通性没有影响,那肯定是要删掉的。现在的问题就是如何找到这些边。
    我们考虑在反拓扑序上求。考虑一个点的所有出边,对于每个指向的点,如果当前还没有找到从当前点到这个点的路径,那么当前的边就要保留,并用这个点能到达的点的集合更新当前点的集合,这个显然能用bitset做到O(nm32)的复杂度。
    但这样做有一个问题,如果12有边,23有边,13有边,那么13这条边是需要被删的,但如果在考虑点1时使用了3,2的顺序,我们就无法求出这样的边。实际上,这是因为从2能到达3,所以我们应该先连接2,就能求出这样的边了。
    上面讨论的特殊情况的通用形式就是,我们贪心地先考虑最“顶端”的那些点,就能考虑到所有要删的边了。这其实就是把所有指向的点按拓扑序排序。那么总复杂度就是O(nm32+mlogm),可以通过此题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,tot=0,first[30010]={0},in[30010]={0},q[30010],pos[30010];
    int son[30010];
    struct edge
    {
        int v,next;
    }e[100010];
    bitset<30010> S[30010];
    
    void insert(int a,int b)
    {
        e[++tot].v=b;
        e[tot].next=first[a];
        first[a]=tot;
        in[b]++;
    }
    
    void toposort()
    {
        int t=0;
        for(int i=1;i<=n;i++)
            if (!in[i])
            {
                q[++t]=i;
                pos[i]=t;
            }
        for(int i=1;i<=n;i++)
        {
            int v=q[i];
            for(int j=first[v];j;j=e[j].next)
            {
                in[e[j].v]--;
                if (!in[e[j].v])
                {
                    q[++t]=e[j].v;
                    pos[e[j].v]=t;
                }
            }
        }
    }
    
    bool cmp(int a,int b)
    {
        return pos[a]<pos[b];
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            insert(a,b);
        }
    
        toposort();
        int ans=0;
        for(int i=n;i>=1;i--)
        {
            S[q[i]].set(q[i]);
            int siz=0;
            for(int j=first[q[i]];j;j=e[j].next)
                son[++siz]=e[j].v;
            if (!siz) continue;
            sort(son+1,son+siz+1,cmp);
            for(int j=1;j<=siz;j++)
            {
                if (S[q[i]][son[j]]) ans++;
                else S[q[i]]|=S[son[j]];
            }
        }
        printf("%d",ans);
    
        return 0;
    }
  • 相关阅读:
    cast() 函数进行类型转换
    '+' 拼接字符串引起的小事故
    shell统计ip访问情况并分析访问日志
    Windows 环境上域名配置
    WebApi中Route的作用
    Postman测试WebApi使用总结
    C# VS2017新建WepApi
    C# 反射总结
    winform--同一个项目窗体复制
    winform TextBox设置透明
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793279.html
Copyright © 2011-2022 走看看