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