显然是拓扑排序
但是并没有那么简单
看起来需要字典序最小,那就拿个堆代替队列,按照点编号大小拓扑排序,然后你就WA了;还不服输,按照能够到达的最小编号的点为第一关键字,点的编号为第二关键字拓扑排序,结果还是WA了,因为这种贪心只能保证最小的在最前面,不能保证最小的在最前面的前提下次小在最前面……
正着不对,不妨倒着考虑
既然编号小的要尽可能在前面访问,那么编号最大的一定要尽可能在最后面。也就是说:最后一个访问的一定是当前出度为\(0\)的点中出度最大的点,将它去掉之后出度为\(0\)的点中编号最大的点会在第\(N-1\)个访问……
那么正确的贪心策略就是:反图上拓扑排序,贪心地选择当前入度为\(0\)的点中编号最大的,这样就可以得到一个正确的排列了。
#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c)){
if(c == '-')
f = 1;
c = getchar();
}
while(isdigit(c)){
a = (a << 3) + (a << 1) + (c ^ '0');
c = getchar();
}
return f ? -a : a;
}
#define PII pair < int , int >
const int MAXN = 1e5 + 7;
struct Edge{
int end , upEd;
}Ed[MAXN];
int head[MAXN] , in[MAXN] , ans[MAXN];
int N , M , cntEd;
bool vis[MAXN] , ins[MAXN];
inline void addEd(int a , int b){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
++in[b];
}
priority_queue < int > q;
void tSort(){
for(int i = 1 ; i <= N ; ++i)
if(!in[i])
q.push(i);
int cnt = 0;
while(!q.empty()){
int t = q.top();
q.pop();
ans[N - cnt++] = t;
for(int i = head[t] ; i ; i = Ed[i].upEd)
if(!--in[Ed[i].end])
q.push(Ed[i].end);
}
if(cnt < N)
puts("Impossible!");
else{
for(int i = 1 ; i <= N ; ++i)
printf("%d " , ans[i]);
putchar('\n');
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in" , "r" , stdin);
freopen("out" , "w" , stdout);
#endif
for(int D = read() ; D ; --D){
N = read();
M = read();
memset(head , 0 , sizeof(head));
memset(vis , 0 , sizeof(vis));
memset(in , 0 , sizeof(in));
cntEd = 0;
for(int i = 1 ; i <= M ; ++i){
int a = read() , b = read();
addEd(b , a);
}
tSort();
}
return 0;
}