HDU - 5413

题目链接:HDU - 5413


显然,直接暴力维护拓扑序是不行的。

我们考虑从小到大遍历拓扑序,然后对于当前遍历的点,访问他的前驱节点,并且从大到小访问前驱点。

如果存在某个拓扑序大的点可以到这个点,那么当前的这条边就是冗余边。

因为直接维护可达性复杂度太高,故用Bitset优化。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e4+10;
int n,m,deg[N],res;
vector<int> g[N],v[N],ts;	bitset<N> bit[N];
void Top(){
	queue<int> q; for(int i=1;i<=n;i++)	if(!deg[i])	q.push(i); ts.clear();
	while(q.size()){
		int u=q.front();	q.pop();	ts.push_back(u);
		for(auto to:g[u]){
			if(--deg[to]==0)	q.push(to);	v[to].push_back(u);
		}
	}
}
inline void solve(){
	cin>>n>>m;	res=0;
	for(int i=1;i<=n;i++)	g[i].clear(),v[i].clear();
	for(int i=1,a,b;i<=m;i++)	scanf("%d %d",&a,&b),g[a].push_back(b),deg[b]++;
	Top();
	for(int i=1;i<=n;i++)	bit[i].reset(),bit[i].set(i);
	for(int i=0;i<n;i++){
		for(int j=v[ts[i]].size()-1;j>=0;j--){
			int to=v[ts[i]][j];
			if(bit[ts[i]][to])	res++;
			bit[ts[i]]|=bit[to];
		}
	}
	printf("%d\n",res);
}
signed main(){
	int T;	cin>>T;
	while(T--)	solve();
	return 0;
}
发布了716 篇原创文章 · 获赞 244 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/104794007
hdu