BZOJ---4484:[Jsoi2015]最小表示【bitset】

题面:

BZOJ---4484

题意:

给定一张有向无环图,求最多能删多少条边使得原图的联通性不变

分析:

设从一个点出发的一条边能到达的点为一个集合,那么这个点所有出边的集合的并就是该点能到达的点的集合,只需要删掉那些没有做出贡献的边即可,当然需要贪心的删除,先按照每个集合的贡献排序,从大到小依次选,如果当前集合不能做出贡献,那就删除它,这个集合正好可以用bitset表示,按理说复杂度也是(n*m/32),但跑得十分慢

代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn = 3e4+34;
int n,m,u,v,cnt,res,head[maxn],vis[maxn];
struct edge{
    int to,nxt;
}e[maxn<<2];
inline void add(int u,int v){
    e[++cnt].to = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}
bitset<maxn> b[maxn];
#define f first
#define pii pair<bitset<maxn>,int>
bool cmp(pii a,pii b){
    return a.second > b.second;
}
void dfs(int u){
    if(vis[u]) return ;
    vis[u] = 1; b[u].set(u);
    vector<pii> ve;                     //储存每条出边能到达点的集合
    for(int i = head[u]; i ;i=e[i].nxt){
        int v = e[i].to; dfs(v);
        ve.push_back(pii(b[v],b[v].count()));
    }
    sort(ve.begin(),ve.end(),cmp);
    for(int i = 0;i < (int)ve.size(); ++i){
        if((b[u]|ve[i].f) != b[u]) b[u] |= ve[i].f;
        else res++;
    }
}
void solve(){
    for(int i = 1;i <= n; ++i){
        if(!vis[i]) dfs(i);
    }
    printf("%d",res);
}
int main(){
    scanf("%d %d",&n,&m);
    while(m--){
        scanf("%d %d",&u,&v);
        add(u,v);
    }
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41157137/article/details/93376752