码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2020-07-11 09:14:51      阅读:47      评论:0      收藏:0      [点我收藏+]

标签:规则   algorithm   stream   表示   ==   return   最大   pac   mes   

拓扑排序,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\n",ans);
	return 0;
}


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

标签:规则   algorithm   stream   表示   ==   return   最大   pac   mes   

原文地址:https://www.cnblogs.com/whitelily/p/13282149.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!