HDU 4857(拓扑排序反向建边)

题意:有N个人,M个优先级a,b表示a优先于b,并且每个人有个编号,使编号越小的点尽可能在序列前部(不是字典序),输出顺序。

思路:首先想的是正向建边的拓扑,但随之写了一组数据给否定了,然后尝试反向建边,发现每次先对序号大的进行处理,然后送入ans数组中得到的就是正确序列。其实可以想得通,因为每次都对序号大的进行处理,它肯定都会在当前所有可处理的点的后面的,所以一路贪心过去即可。


Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 30005;
const int maxm = 100005;
struct node
{
	int v, next;
}edge[maxm];
int head[maxn], degree[maxn];
int n, m, no;
vector<int> vt;
priority_queue<int> q;
inline void init()
{
	no = 0;
	vt.clear();
	memset(degree, 0, sizeof degree);
	memset(head, -1, sizeof head);
}
int add(int u, int v)
{
	int k = head[u];
	while(k != -1)
	{
		if(edge[k].v == v) return 0;
		k = edge[k].next;
	}
	edge[no].v = v;
	edge[no].next = head[u];
	head[u] = no++;
	return 1;
}
void kahn()
{
	while(!q.empty())
	{
		int tp = q.top(); q.pop();
		vt.push_back(tp);
		int k = head[tp];
		while(k != -1)
		{
			--degree[edge[k].v];
			if(!degree[edge[k].v]) q.push(edge[k].v);
			k = edge[k].next;
		}
	}
}
int main()
{
	int t, a, b, flag;
	scanf("%d", &t);
	for(int _ = 1; _ <= t; ++_)
	{
		scanf("%d %d", &n, &m);
		init();
		for(int i = 1; i <= m; ++i)
		{
			scanf("%d %d", &a, &b);
			if(add(b, a)) ++degree[a];
		}
		for(int i = 1; i <= n; ++i) 
		if(!degree[i]) q.push(i);
		kahn(); flag = 0;
		for(int i = vt.size()-1; i >= 0; --i)
		{
			if(flag) printf(" ");
			printf("%d", vt[i]); flag = 1;
		}
		puts("");
	}
	return 0;
}

对于DFS版拓扑,估计只适用于已知符合拓扑条件然后去求一个任意拓扑序列吧。


继续加油~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值