Problem Description
糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。
现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。
同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。
负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。
那么你就要安排大家的顺序。我们保证一定有解。
Input
第一行一个整数T(1 <= T <= 5),表示测试数据的个数。
然后对于每个测试数据,第一行有两个整数n(1 <= n <= 30000)和m(1 <= m <= 100000),分别表示人数和约束的个数。
然后m行,每行两个整数a和b,表示有一个约束a号必须在b号之前。a和b必然不同。
Output
对每个测试数据,输出一行排队的顺序,用空格隔开。
Sample Input
1 5 10 3 5 1 4 2 5 1 2 3 4 1 4 2 3 1 5 3 5 1 2
Sample Output
1 2 3 4 5
为什么要反向拓扑排序呢?举个例子:6 -> 3 -> 1 和 5 -> 4 -> 2 。直接拓扑排序的结果是:5 4 2 6 3 1 ,结果是错误的,因为我们可以把1号安排到更前面的位置 即:6 3 1 5 4 2(正确答案)。
所以我们用逆向思维思考一下先考虑哪些点应该靠后释放,这样的话我们就可以把拓扑关系反过来(即弧头和弧尾调换),然后做拓扑排序,然后我们可以根据原来的弧头(现在变成弧尾)的大小来释放结点,由于现在的问题变成哪些最后释放,那么就应该优先考虑弧尾(原来的弧头)比较大的,可以通过优先队列来解决。
#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 110
#define qx std::ios::sync_with_stdio(false)
#define N 2100
using namespace std;
int in[31000],a,b,m,n;
vector<int> v[30100];
int main(){
int t;qx;//cin太慢会超时
cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=n;i++)
v[i].clear();
memset(in,0,sizeof in);
vector<int> ans;
priority_queue<int>q;
for(int i=0;i<m;i++){
cin>>a>>b;
v[b].push_back(a);
in[a]++;
}
for(int i=1;i<=n;i++){
if(in[i]==0){
q.push(i);
}
}
while(!q.empty()){
int p=q.top();q.pop();
ans.push_back(p);
for(int i=0;i<v[p].size();i++){
in[v[p][i]]--;
if(in[v[p][i]]==0)
q.push(v[p][i]);
}
}
for(int i=ans.size()-1;i>0;i--)
cout<<ans[i]<<" ";
cout<<ans[0]<<endl;
}
return 0;
}