[HNOI2015]菜肴制作

洛咕

题意:给定(m)个有序对((a,b)),构造一个(n)的排列,满足(m)个有序对中(a)均排在(b)的前面,且1尽量靠前,在1尽量靠前的前提下,2尽量靠前,....以此类推.(n,m<=100000.)

分析:结论题???还是不会证结论的那种.

首先一个合法的排列就是反向图的拓扑序,然后是要让(1,2...)尽量靠前,那么就是反向图的拓扑序的字典序尽量大,这个我们直接开一个大根堆维护点的编号就好了.

具体说来,反向建图,然后把度数为0的点丢进大根堆里跑拓扑排序即可.如果跑完拓扑之后的排列里面没有n个数,判断无解,否则倒序输出就是答案了.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=100005;
int deg[N],Ans[N];
int tot,head[N],nxt[N],to[N];
priority_queue<int>q;
inline void add(int a,int b){
	nxt[++tot]=head[a];head[a]=tot;to[tot]=b;
}
int main(){
	int T=read();
	while(T--){
		tot=0;memset(head,0,sizeof(head));
		memset(deg,0,sizeof(deg));
		int n=read(),m=read();
		for(int i=1;i<=m;++i){
			int a=read(),b=read();
			add(b,a);++deg[a];
		}
		for(int i=1;i<=n;++i)if(!deg[i])q.push(i);
		int ans=0;
		while(q.size()){
			int u=q.top();q.pop();
			Ans[++ans]=u;
			for(int i=head[u];i;i=nxt[i]){
				int v=to[i];--deg[v];
				if(!deg[v])q.push(v);
			}
		}
		if(ans!=n)puts("Impossible!");
		else{
			for(int i=ans;i>=1;--i)
				printf("%d ",Ans[i]);
			printf("
");
		}
	}
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/11543854.html