题目链接:BZOJ 4010
题解:
拓扑排序是比较明显的,两种思路:
- 正着,每次找字典序最小的
- 倒着,每次找字典序最大的
如果有限制条件<4,1>,那么最优解是(4,1,2,3),但正着找字典序最小找到的却是 (2,3,4,1),因此正着行不通。反着的正确性想想似乎有道理,反向建边,每次字典序最大的放到最后,就能让字典序小的尽量靠前了吧。(我不会证明QwQ……)
code(代码还是比较简单的(⊙v⊙))
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
int t,tot,a[100005],head[110000],in[110000];
priority_queue < pair<int,int> , vector<pair<int,int> > >q;
bool vis[100001];
struct edge{
int to,ne;
}e[220000];
void push(int x,int y)
{
e[++tot].to=y; e[tot].ne=head[x]; head[x]=tot; in[y]++;
}
using namespace std;
int main()
{
scanf("%d",&t);
int n,m;
while (t--)
{
memset(vis,false,sizeof(vis));
memset(a,0,sizeof(a));
memset(in,0,sizeof(in));
memset(head,0,sizeof(head));
tot=0;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
push(y,x);
}
int sum=0;
for (int i=1;i<=n;i++)
if (in[i]==0) q.push(make_pair(i,0));
int cnt=0;
while (!q.empty())
{
int now=q.top().first; q.pop();
if (vis[now]) continue;
vis[now]=true;
a[++cnt]=now;
for (int i=head[now];i;i=e[i].ne)
{
int v=e[i].to;
in[v]--;
if (in[v]==0) q.push(make_pair(v,0));
}
}
if (cnt!=n) printf("Impossible!\n");
else
{
for (int i=1;i<=n;i++)
printf("%d ",a[n-i+1]);
printf("\n");
}
}
return 0;
}