P3243 [HNOI2015]菜肴制作

萌新今天刚刚接触拓扑排序,找到了一些题,然后就来做这道题紫题了(雾)

还是不要被题目的难度吓到吧,其实这道题挺模板的,思路感觉也比较好想,但是关于证明这些,我太菜,并不会。是一道非常好的入手拓扑排序的题,不像其他题目那样难想

对于一个限制 <i,j>,其实表示的就是 i 必须在 j 之前完成,我们把这个条件转化成图的形式就是 i 到 j 有一条有向边,然后就可以试着往拓扑排序的方向思考了

拓扑排序最基础的应用是什么,可以把它当做学习一个东西(比如语文吧),你要学习一篇文章,你总得先学会认字吧,学会认字肯定就要学会拼音,那么你要提前学习的东西就是前置知识,就相当于以上提到的 j (你要完成 j ,你必须先学会 i )。那这么一看,裸裸的拓扑排序

但是有一点变化的是什么呢?题目中的编号越小,表示它的预估质量越高(显而易见,这里指的不是字典序),所以对于编号小的,我们希望它在前面,而编号的就往后面放

因为如果正序按题目建边的话,假如1号点的入度不为1,而2的入度为0,我们应该先把限制1的点全部删掉,再把1弄出来,再去删2,这样才能保证最优,但是正序直接建立的话我们会把2直接删去

所以我们应该倒序建立。我们可以通过大根堆来实现把编号越大的越先处理,然后再倒序输出答案就可以了(可以理解为先把价值低的存储下来,价值高的就在后面,这个时候倒序输出就可以保证价值越高的越先做)

然后剩下了一个 Impossible ,这个也很简单,拓扑排序的另外一种应用,判断是否有环存在就可以了

#include<bits/stdc++.h>
using namespace std;
const int MAXN=500000;
int d;
int n,m;
int head[MAXN],tot;
struct node{
	int net,to;
}e[MAXN];
void add(int x,int y){
	e[++tot].to=y;
	e[tot].net=head[x];
	head[x]=tot;
} //链式前向星存储边,邻接矩阵一般来说会慢一点 
int ru[MAXN]; //入度 
int ans[MAXN],now; //存储答案 
bool toop(){  //直接写成bool类型容易判断一些 
	priority_queue<int>q; //堆(优先队列) STL确实很方便 
	for(register int i=1;i<=n;i++){
		if(ru[i]==0) q.push(i); //入度为0的加入堆 
	}
	while(!q.empty()){
		int x=q.top();
		q.pop();
		ans[++now]=x; //存储答案 
		for(register int i=head[x];i;i=e[i].net){
			ru[e[i].to]--; //这个点删去了,它能到的点的入度就要-- 
			if(ru[e[i].to]==0){ //入度为0的加入堆中 
				q.push(e[i].to);
			} 
		}
	}
	if(now==n) return true; //如果刚好处理了n个,说明没有环 
	return false; //否则有环,出错 
}
int main(){
	scanf("%d",&d);
	while(d--){
		now=0,tot=0;
		for(register int i=1;i<=n;i++) ru[i]=0,ans[i]=0;
		memset(e,0,sizeof e);
		memset(head,0,sizeof head); //注意清空数组,建议大家自己如果能手动清空就别用memset 
		scanf("%d%d",&n,&m);
		for(register int i=1;i<=m;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			add(y,x);
			ru[x]++; //灵魂的反向建边 
		}
		//bool k=toop(); 
		//这个地方挺玄学的吧,我最开始声明了一个新变量判断是否有环(如上) 
		//然后它就超时了,所以这里直接写成toop()直接判断就可以了 
		if(toop()==false) puts("Impossible!"); //如果有环就不可能 
		else{
			for(register int i=now;i>=1;i--) printf("%d ",ans[i]); //倒序输出答案 
			puts("");
		}
	}
	return 0;
}

关于拓扑排序的一些具体介绍,大家可以去看看 洛谷日报 快速入手拓扑排序这不会被算作抄袭吧) ,然后宣传一下自己同桌的博客

posted @ 2020-06-30 20:05  Poetic_Rain  阅读(83)  评论(0编辑  收藏  举报