拓扑序分析以及例题

分析

拓扑序本质上就是一个先后顺序,通过入度的区别来先后入队,使得入队的顺序保证一个严格的递增。

例题

acwing 1192.奖金

通过拓扑序分析就行,既可以判环也可以判是否联通

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5,M = 2 * 1e4 + 5;
int din[N];
int e[M],ne[M],h[N],idx;
int salary[N];
int n,m;
void add(int fr,int to){
	idx ++;
	e[idx] = to;
	ne[idx] = h[fr];
	h[fr] = idx;
}
bool topsort(){
	queue <int> q;
	int cnt = 0;
	for(int i = 1;i <= n;i ++){
		if(! din[i])
			q.push(i),salary[i] = 100,cnt ++;
	}
	while(! q.empty()){
		int f = q.front();
		q.pop();
		for(int i = h[f];i;i = ne[i]){
			-- din[e[i]];
			if(din[e[i]] == 0){
				salary[e[i]] = salary[f] + 1;
				cnt ++;
				q.push(e[i]);
			}
		}
	}
	return cnt == n;
}
int main(){	
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= m;i ++){
		int a,b;
		scanf("%d%d",&a,&b);
		din[a] ++;
		add(b,a);
	}
	if(! topsort()){
		puts("Poor Xed");
		exit(0);
	}else{
		int res = 0;
		for(int i = 1;i <= n;i ++)
			res += salary[i];
		cout << res;
	}
	return 0;
}

可达性统计

先拓扑序再用bitset统计,思路码一下

#include <bits/stdc++.h>
using namespace std;
const int N = 3e4 + 5;
int e[N],ne[N],h[N],idx;
int a[N];
int din[N];
int cnt;
int n,m;
bitset <N> f[N];
void add(int fr,int to){
	idx ++;
	e[idx] = to;
	ne[idx] = h[fr];
	h[fr] = idx;
}
void topsort(){
	queue <int> q;
	for(int i = 1;i <= n;i ++)
		if(! din[i])
			q.push(i);
	while(! q.empty()){
		int f = q.front();
		q.pop();
		a[++ cnt] = f;
		for(int i = h[f];i;i = ne[i]){
			din[e[i]] --;
			if(! din[e[i]])
				q.push(e[i]);
		}
	}
}
int main(){
	
	cin >> n >> m;
	for(int i = 1;i <= m;i ++){
		int a,b;
		scanf("%d%d",&a,&b);
		add(a,b);
		din[b] ++;
	}
	topsort();
	for(int i = cnt;i >= 1;i --){
		int k = a[i];
		f[k][k] = 1;
		for(int j = h[k];j;j = ne[j])
			f[k] |= f[e[j]];
	}
	for(int i = 1;i <= n;i ++)
		cout << f[i].count() << endl;
	return 0;
}

acwing.456 车站分级

这道题目,原先我在洛谷做过,当时用暴力连边跑拓扑的方法通过了,但其实复杂度有点高,假设有1000个点,每条车站就要连2e4条边左右,一共就要连2e7条边,复杂度非常高。但是通过建立一个虚点,每条车站至多只需要连1e3条边,一下子少了很多。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5,M = 1e6 + 5;
int e[M],ne[M],w[M],h[N],idx;
bool stop[N];
int din[N],ans[N],cnt;
int f[N];
int n,m;
void add(int fr,int to,int dis){
	din[to] ++;
	idx ++;
	e[idx] = to;
	ne[idx] = h[fr];
	h[fr] = idx;
	w[idx] = dis;
}
void toposort(){
	queue <int> q;
	for(int i = 1;i <= n + m;i ++)
		if(! din[i])
			q.push(i);
	while(! q.empty()){
		int fr = q.front();
		q.pop();
		ans[++ cnt] = fr;
		for(int i = h[fr];i;i = ne[i]){
			din[e[i]] --;
			if(! din[e[i]]){
				q.push(e[i]);
			}
		}
	}
}
int main(){
	cin >> n >> m;
	for(int i = 1;i <= m;i ++){
		int x;
		scanf("%d",&x);
		memset(stop,false,sizeof stop);
		int start = 1e3 + 5;
		int end = 0;
		for(int j = 1;j <= x;j ++){
			int tmp;
			cin >> tmp;
			stop[tmp] = true;
			start = min(start,tmp);
			end = max(end,tmp);
		}
		for(int j = start;j <= end;j ++){
			if(stop[j])
				add(j,n + i,0);
			else
				add(n + i,j,1);
		}
	}
	toposort();
	for(int i = 1;i <= n + m;i ++) 
	    f[i] = 1;
	int maxn = 0;
	for(int i = 1;i <= cnt;i ++){
		int k = ans[i];
		for(int j = h[k];j;j = ne[j]){
			f[e[j]] = max(f[e[j]],f[k] + w[j]);
		}
	}
	for(int i = 1;i <= n;i ++)
	    maxn = max(maxn,f[i]);
	cout << maxn;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值