POJ3687 球的标签(拓扑排序+优先队列)

给定N个球,这些球的编号分别是1-N中的某个数字,它们的重量也分别是1-N中的某个数字,任意两个球的编号和重量不相等。

给定一些类似a<b的约束,表示编号为a的球比编号为b的球轻。要求符合约束条件的各个球的重量。若答案有多种,则输出的答案必须让编号为1的球重量尽量轻,接着是编号为2的球重量尽量轻,一直到编号为N的球尽量轻。

这道题是一个拓扑排序问题,把每个编号的球看成一个点,把约束看成点之间的边,构造出一个有向图进行拓扑排序。但由于题目要求输出的答案必须是编号小的球重量尽量轻,因此如果直接拓扑排序,则得到的答案不满足条件。解决的方法是改变每条边的方向,并且使用优先队列来存放入度为0的点,优先队列的队头是入度为0的点中编号最大的,这样的反向拓扑得到的排列刚好是题目要求答案的反向排列。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 205;
const int M = 40005;
struct Edge
{
	int pos;
	int next;
};
Edge edge[M];
bool vis[N][N];
int cur;
int neigh[N];
int n, m;
int indegree[N];
int pq[N], pqsize;
int ans[N], k;

void init()
{
	pqsize = 0;
	for (int i = 1; i <= n; ++i) neigh[i] = -1;
	for (int i = 1; i <= n; ++i) indegree[i] = 0;
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= n; ++j)
		{
			vis[i][j] = false;
		}
	}
	cur = 0;
}

void upward(int pos)
{
	if (pos == 1) return;
	if (pq[pos] > pq[pos >> 1])
	{
		swap(pq[pos], pq[pos >> 1]);
		upward(pos >> 1);
	}
}

void downward(int pos) 
{  
	if ((pos << 1) + 1 <= pqsize)  
	{  
		if (pq[pos << 1] > pq[(pos << 1) + 1] && pq[pos << 1] > pq[pos])  
		{  
			swap(pq[pos << 1], pq[pos]);  
			downward(pos << 1);  
		}  
		else if (pq[pos << 1] < pq[(pos << 1) + 1] && pq[(pos << 1) + 1] > pq[pos])  
		{  
			swap(pq[(pos << 1) + 1], pq[pos]);  
			downward((pos << 1) + 1);  
		}  
	}  
	else if ((pos << 1) <= pqsize)
	{  
		if (pq[pos << 1] > pq[pos])  
		{  
			swap(pq[pos << 1], pq[pos]);  
			downward(pos << 1);  
		}  
	}  
}  

void enque(int val)
{
	pq[++pqsize] = val;
	upward(pqsize);
}

int deque()
{
	int ret = pq[1];
	pq[1] = pq[pqsize--];
	downward(1);
	return ret;
}

int main()
{
	int T;
	int beg, end, t;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &n, &m);
		init();
		for (int i = 0; i < m; ++i)
		{
			scanf("%d%d", &end, &beg);
			if (vis[beg][end]) continue;
			vis[beg][end] = true;
			edge[cur].pos = end;
			edge[cur].next = neigh[beg];
			neigh[beg] = cur;
			++cur;
			++indegree[end];
		}
		for (int i = 1; i <= n; ++i)
		{
			if (indegree[i] == 0) enque(i);
		}
		k = n;
		while (pqsize > 0)
		{
			t = deque();
			ans[t] = k--;
			int e = neigh[t];
			while (e != -1)
			{
				--indegree[edge[e].pos];
				if (indegree[edge[e].pos] == 0) enque(edge[e].pos);
				e = edge[e].next;
			}
		}
		if (k == 0)
		{
			for (int i = 1; i < n; ++i) printf("%d ", ans[i]);
			printf("%d\n", ans[n]);
		}
		else printf("-1\n");
	}
	return 0;
}
    原文作者:拓扑排序
    原文地址: https://blog.csdn.net/alongela/article/details/8258115
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞