拓扑排序,bitset~[JSOI2015]最小表示

Posted ccsu_madoka

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拓扑排序,bitset~[JSOI2015]最小表示相关的知识,希望对你有一定的参考价值。

拓扑排序,bitset~[JSOI2015]最小表示

传送门

题意:在有向无环图中删尽可能多的边,使图连通性不变,输出最大数量。

题解:写这题主要就是学一下bitset的用法,首先如果一个x到y的边可以删的话,说明从x到y有别的路可以走,从此还可以想到解此题的一个关键,如y可以到z,然后x连着y与z,我先让x和y连起来,则一次完成了x与y连通与z连通的任务,那么这个时候x到z就是条费边了,可加入答案,所以我们要将点的边进行排序,规则就是拓扑排序靠后的点排在后面,之后就是怎么记录y连着z,还有判断x到z是费边时怎么记录x已经与z连接起来了,这里我们用bitset去记录,这里就说几个关键的操作,bitset[x] [y]=1说明x已连接上y,bitset[x]|=bitset[y] 的意思是将y连接到的其他点也加入x。

总结一下,先用拓扑排序列出搜点的顺序,再从无出点的点(逆序)开始,往前加边,同时对边排序。

#include<iostream>
#include<algorithm>
#include<map>
#include<bitset>
#include<vector>
#include<queue>
using namespace std;
#define pb push_back
int n,m,v,u,ru[30007],dis[30007];
vector<int>ho[30007];
vector<int>edg;
queue<int>sa;
bitset<30007>se[30007];
bool cmp(int a,int b){
	return dis[a]<dis[b];
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&u,&v);
		ho[u].pb(v);
		ru[v]++;
	}
	for(int i=1;i<=n;i++){
		if(ru[i]==0)sa.push(i);
	}
	int cnt=0;
	while(!sa.empty()){
		int lin=sa.front();
		sa.pop();
		dis[lin]=++cnt;
		edg.pb(lin);
		for(int i=0;i<ho[lin].size();i++){
			ru[ho[lin][i]]--;
			if(ru[ho[lin][i]]==0){
				sa.push(ho[lin][i]);
			}
		}
	}
	for(int i=1;i<=n;i++){
		sort(ho[i].begin(),ho[i].end(),cmp);
	}
	int len=edg.size()-1,lin,lin2,ans=0;
	for(int i=len;i>=0;i--){
		lin=edg[i];
		se[lin][lin]=1;
		for(int j=0;j<ho[lin].size();j++){
			lin2=ho[lin][j];
			if(se[lin][lin2]==1){
				ans++;
			}
			else{
				se[lin]|=se[lin2];
			}
		}
	}
	printf("%d
",ans);
	return 0;
}


以上是关于拓扑排序,bitset~[JSOI2015]最小表示的主要内容,如果未能解决你的问题,请参考以下文章

「JSOI2015」最小表示

[JSOI2015]最小表示

[JSOI2019]精准预测(2-SAT+拓扑排序+bitset)

BZOJ2208 [Jsoi2010]连通数

[bzoj2208][Jsoi2010]连通数_bitset_传递闭包floyd

164. 可达性统计拓扑排序 / bitset