我对贪心的理解:https://www.cnblogs.com/AKMer/p/9776293.html
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4010
对于这道题,比较麻烦的是他要求的并不是完全字典序最小的一个序列,而是满足序号从小到大尽量要靠前。所以这就不能直接每次拓扑排序直接取最小值了,也许较大值取出来后就可以取更小的值了呢。
比如(2)号菜必须在(5)号菜后面处理,(3)号菜必须在(4)号菜后面处理。那么直接按字典序最小就是(1,4,3,5,2)了,而题意要求的却是(1,5,2,4,3)。
既然这个东西这么麻烦使我们无法很快的判断出哪个值应该放在前面,那么我们就不去想哪个值放在前面了嘛。我们就去想,较大的值是不是应该放在更后面。
结果发现还真是这样,那么我们就直接倒着做,每次取可取值里最大的值放在后面就行了,拓扑排序加堆优化就(Over)了。
时间复杂度:(O(nlogn))
空间复杂度:(O(n))
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;
int n,m,tot,cnt,x,y;
int deg[maxn],ans[maxn];
int now[maxn],pre[maxn],son[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
void clear() {
cnt=tot=0;
memset(now,0,sizeof(now));
memset(deg,0,sizeof(deg));
}
void add(int a,int b) {
pre[++tot]=now[a];
now[a]=tot;son[tot]=b;
deg[b]++;
}
struct Heap {
int tot;
int node[maxn];
void ins(int x) {
node[++tot]=x;
int pos=tot;
while(pos>1) {
if(node[pos]>node[pos>>1])
swap(node[pos],node[pos>>1]),pos>>=1;
else break;
}
}
int pop() {
int res=node[1];
node[1]=node[tot--];
int pos=1,son=2;
while(son<=tot) {
if(son<tot&&node[son|1]>node[son])son|=1;
if(node[son]>node[pos])
swap(node[son],node[pos]),pos=son,son=pos<<1;
else break;
}
return res;
}
}T;
void work() {
for(int i=1;i<=n;i++)
if(!deg[i])T.ins(i);
while(T.tot) {
int u=T.pop();
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!(--deg[v]))T.ins(v);
ans[++cnt]=u;
}
}//拓扑排序加大根堆优化
void print_ans() {
for(int i=n;i>1;i--)
printf("%d ",ans[i]);
printf("%d
",ans[1]);//输出也要倒着
}
int main() {
int T=read();
while(T--) {
n=read(),m=read();clear();
for(int i=1;i<=m;i++)
x=read(),y=read(),add(y,x);//y要比x后制作,所以y向x连边
work();
if(cnt!=n)puts("Impossible!");//cnt不等于n说明有环,就GG了
else print_ans();
}
return 0;
}