一开始看成字典序最小。。后来想到不对又YY了一种奇怪的方法,不过还是错的。。
正解是倒着来,边都倒着加,然后求一个字典序最大的拓扑序,反过来就是答案了。。一开始想不通为什么是这样,仔细想想应该没错。。如果没有选最大的,就让一个更小的放在了后面,而它本可以在更前的,所以一定要选最大的。。感觉和NOI2009变换序列的思路有点像,倒过来把要先满足的放到后面它自然就会满足了。。
#include<cstdio>
#include<iostream>
#include<memory.h>
#define N 100005
using namespace std;
struct edge{
int e,next;
}ed[N];
int T,n,m,i,j,ne,s,e,nd,heap[N],in[N],u[N],a[N],ans[N];
bool f;
void add(int s,int e)
{
ed[++ne].e=e;ed[ne].next=a[s];a[s]=ne;
}
bool dfs(int x)
{
u[x]=-1;
bool f=true;
for (int j=a[x];j;j=ed[j].next)
{
if (u[ed[j].e]==-1) return false;
else if (u[ed[j].e]==0) f=f&&dfs(ed[j].e);
}
u[x]=1;
return f;
}
void up(int x)
{
while (x>1&&heap[x]>heap[x>>1]) swap(heap[x],heap[x>>1]),x>>=1;
}
void ins(int x)
{
heap[++nd]=x;
up(nd);
}
void del()
{
heap[1]=heap[nd--];
int x=1;
while (x*2<=nd)
{
x<<=1;
if (x<nd&&heap[x+1]>heap[x]) x++;
if (heap[x]>heap[x>>1]) swap(heap[x],heap[x>>1]);else break;
}
}
int main()
{
freopen("dishes.in","r",stdin);
// freopen("dishes.out","w",stdout);
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) a[i]=0,in[i]=0,u[i]=0;
ne=0;
for (i=1;i<=m;i++)
{
scanf("%d%d",&s,&e);
add(e,s);in[s]++;
}
f=true;
for (i=1;i<=n;i++)
if (!u[i]) f=f&&dfs(i);
if (!f)
{
printf("Impossible!\n");
continue;
}
nd=0;
for (i=1;i<=n;i++)
if (!in[i]) ins(i);
for (i=n;i;i--)
{
ans[i]=heap[1];
del();
for (j=a[ans[i]];j;j=ed[j].next)
if (--in[ed[j].e]==0) ins(ed[j].e);
}
for (i=1;i<=n;i++) printf("%d ",ans[i]);printf("\n");
}
}