题面:
题意:
给定一张有向无环图,求最多能删多少条边使得原图的联通性不变
分析:
设从一个点出发的一条边能到达的点为一个集合,那么这个点所有出边的集合的并就是该点能到达的点的集合,只需要删掉那些没有做出贡献的边即可,当然需要贪心的删除,先按照每个集合的贡献排序,从大到小依次选,如果当前集合不能做出贡献,那就删除它,这个集合正好可以用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;
}