卧薪尝胆,厚积薄发。
HNOI2015 菜肴制作
Date: Tue Sep 25 08:08:24 CST 2018 In Category: NoCategory

Description:

求一个满足一些限制条件,尽量小的数尽量靠前的排列。
$1\leqslant n \leqslant 100000$

Solution:

直接求字典序最小的拓扑排序是不正确的,因为那样是保证第一个位置上的数尽量小,然后第二个位置上的数尽量小,而不是较小的数尽量靠前。
由于我们不知道有谁限制了最小的数,也就是说不能知道最小的数前面必须有谁,而要想让最小的数尽量靠前,这些数又必须先出现,所以正着考虑是不能做的,那就倒着考虑,在反图上求一个字典序最大的拓扑序,那么最小的数一定被留到了尽量靠后的位置,这正是我们想要的。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 100010
int ind[MAXN];
struct edge
{
int to,nxt;
}e[MAXN];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++ind[b];
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
return;
}
int ans[MAXN];
void work()
{
memset(lin,0,sizeof(lin));
edgenum = 0;
scanf("%d%d",&n,&m);
int a,b;
memset(ind,0,sizeof(ind));
for(int i = 1;i <= m;++i)
{
scanf("%d%d",&a,&b);
add(b,a);
}
priority_queue<int> q;
for(int i = 1;i <= n;++i)
if(ind[i] == 0)
q.push(i);
int t = n;
while(!q.empty())
{
int k = q.top();q.pop();
ans[t--] = k;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
--ind[e[i].to];
if(ind[e[i].to] == 0)
{
q.push(e[i].to);
}
}
}
for(int i = 1;i <= n;++i)
{
if(ind[i] != 0)
{
puts("Impossible!");
return;
}
}
for(int i = 1;i <= n;++i)
{
printf("%d ",ans[i]);
}
puts("");
return;
}
int main()
{
int testcases;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡