HNOI 2015 菜肴制作

HNOI 2015 菜肴制作

​ 题目链接:HNOI2015 菜肴制作


​ 显然的拓扑排序,一个很明显的想法是建图跑拓扑排序然后用小根堆来替换队列。但是这个想法明显有误,举个例子,现在我们能做 \(3,4\),而 \(4\)\(1\) 的制作有利,\(3\)\(1\) 的制作无益,那么我们应该先做 \(4\) 而不是 \(3\)。那么我们可以倒着思考,我们将原图的边的方向取反,然后用大根堆跑一趟拓扑排序,相当于我们倒着填一个顺序,当前入度为 \(0\) 的点肯定有一个是要放在当前位置上的,那么我们就让大的编号的点放在后面。接下来就是一个拓扑排序的模板。时间复杂度 \(O(n+m)\)

代码如下:

#include<bits/stdc++.h>
#define ls(k) (k<<1)
#define rs(k) (k<<1|1)
using namespace std;
const int MAXN = 1e5+5; 
int n,m,ans[MAXN],in[MAXN];
vector <int> e[MAXN];
bool topo()
{
	priority_queue <int> q;
	for(int i=1;i<=n;++i)
		if(!in[i]) q.push(i);
	int cnt=0;
	while(!q.empty())
	{
		int p=q.top();
		q.pop();
		ans[++cnt]=p;
		for(int i=0;i<e[p].size();++i)
		{
			int to=e[p][i];
			in[to]--;
			if(!in[to]) q.push(to);
		}
	}
	for(int i=1;i<=n;++i)
		if(in[i]) return true;
	return false;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d %d",&n,&m);
		for(int i=1;i<=n;++i) e[i].clear();
		memset(in,0,sizeof in);
		for(int i=1;i<=m;++i)
		{
			int u,v;
			scanf("%d %d",&u,&v);
			e[v].push_back(u);
			in[u]++;
		}
		if(topo()) printf("Impossible!\n");
		else
		{
			for(int i=n;i>=1;--i) printf("%d ",ans[i]);
			printf("\n");
		}
	}
	return 0;
}

总结:拓扑排序好题。

posted @ 2021-10-06 14:36  夜空之星  阅读(32)  评论(0编辑  收藏  举报