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

来源:互联网 发布:算法设计举例 编辑:程序博客网 时间:2024/05/29 13:54

给定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;}


原创粉丝点击