[JSOI2015]最小表示

之前连bitset都不会写......为了写这道题去学习了一下bitset的用法

首先要得到一个很显然的结论,就是如果\(x\)和\(y\)之间的边可以被删去,那么\(x\)一定可以通过别的路径走到\(y\),然后在这里我们就需要用bitset来维护点与点之间的连通性

因为这是一个有向无环图,所以我们直接拓扑排序,然后从出度为零的点逆序入队,将每一个结点的子节点按照到出度为零的点的距离由大到小排序,可以保证最优,然后判一下\(bit[x][son]\)是不是1,如果是1就说明这条边是可以删掉的

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,r[30003],ru[30003],p,hd,st[30003],ans;
queue<int>q;
vector<int>l[30003];
bitset<30003>bit[30003];
int cmp(int nx,int ny)
{
    return r[nx]>r[ny];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        l[x].push_back(y),ru[y]++;
    }
    for(int i=1;i<=n;i++)
        if(ru[i]==0)
            q.push(i);
    while(!q.empty())
    {
        p=q.front(),q.pop(),hd++,st[hd]=p;
        for(int j=0;j<l[p].size();j++)
        {
            ru[l[p][j]]--;
            if(ru[l[p][j]]==0)
                q.push(l[p][j]);
        }       
    }
    for(int i=n;i>=1;i--)
    {
        x=st[i],bit[x][x]=1;
        sort(l[x].begin(),l[x].end(),cmp);
        for(int j=0;j<l[x].size();j++)
        {
            r[x]=max(r[l[x][j]]+1,r[x]);
            if(bit[x][l[x][j]]==1)
                ans++;
            else
                bit[x]|=bit[l[x][j]];
        }
    }
    cout<<ans;
    return 0;
}
上一篇:2020牛客寒假算法基础集训营2 F拿物品


下一篇:优先队列的写法