[HNOI2015]菜肴制作 题解

传送门:[HNOI2015]菜肴制作
根据题目的描述,我们要做的首先是一步一步的分析:
这个题肯定是拓扑排序无疑,因为要求的是满足固定条件(有向图的连边)的某种排列,而难点就在于如何拓扑排序。
根据题目的描述,我们首先想到的是根据字典序大小进行排序,那么我们就举例几组数据来验证一下是否正确,那么先看下面这一组数据:
1
5 2
3 2
4 1
根据我们的猜想,数据的输出应该是:
3 2 4 1 5
但经过分析,实际上应该是:
4 1 3 2 5
那么就肯定不是根据字典序来进行拓扑排序了。那是根据什么呢?
答案是根据反图的较大字典序进行倒序输出,这样就可以保证最小的值尽量靠前了
代码:

#include
#include
#include
#include
#include
#include
#include
#define maxn 300030
using namespace std;
inline int read(){
	int a=0,k=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
	while(c<='9'&&c>='0'){a=a*10+c-'0';c=getchar();}
	return a*k;
}

struct Edge{
	int to,next;
}edge[maxn];
int head[maxn],cnt,du[maxn];
void add(int x,int y){
	edge[++cnt].to=y;
	edge[cnt].next=head[x];
	head[x]=cnt;
}
priority_queue <int> torp;
int n,m,d,x,y,tot,toop[maxn];
bool imp;
int main(){
	d=read();
	while(d--){
		memset(head,0,sizeof(head));
		memset(du,0,sizeof(du));
		memset(edge,0,sizeof(edge));
		imp=0,tot=0;
		int sum=0;
		n=read();m=read();
		for(int i=1;i<=m;i++){
			x=read(),y=read();
			add(y,x);du[x]++;
			if(x==y){
				printf("Impossible!\n");
				imp=1;
			}
		}
		if(imp)continue;
		for(int i=1;i<=n;i++){
			if(!du[i])torp.push(i),sum++;
		}
		while(!torp.empty()){
			int u=torp.top();torp.pop();
			toop[++tot]=u;
			for(int i=head[u];i;i=edge[i].next){
				int v=edge[i].to;
				du[v]--;
				if(!du[v])torp.push(v);
			}
		}
		if(tot<n){
			printf("Impossible!\n");
			continue;
		}
		for(int i=n;i>=1;i--){
			printf("%d ",toop[i]);
		}
		printf("\n");
	}
	return 0;
}

你可能感兴趣的:(图论,of,OI,拓扑排序,图论)