ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P3243 [HNOI2015]菜肴制作

2022-01-26 15:03:49  阅读:166  来源: 互联网

标签:菜肴 顺序 限制 int HNOI2015 P3243 尽量 制作


题面

知名美食家小 A 被邀请至 ATM 大酒店,为其品评菜肴。ATM 酒店为小 A 准备了 \(n\) 道菜肴,酒店按照为菜肴预估的质量从高到低给予 \(1\) 到 \(n\) 的顺序编号,预估质量最高的菜肴编号为 \(1\)。

由于菜肴之间口味搭配的问题,某些菜肴必须在另一些菜肴之前制作,具体的,一共有 \(m\) 条形如 \(i\) 号菜肴必须先于 \(j\) 号菜肴制作的限制,我们将这样的限制简写为 \((i,j)\)。

现在,酒店希望能求出一个最优的菜肴的制作顺序,使得小 A 能尽量先吃到质量高的菜肴:

也就是说,

  1. 在满足所有限制的前提下,\(1\) 号菜肴尽量优先制作。

  2. 在满足所有限制,\(1\) 号菜肴尽量优先制作的前提下,\(2\) 号菜肴尽量优先制作。

  3. 在满足所有限制,\(1\) 号和 \(2\) 号菜肴尽量优先的前提下,\(3\) 号菜肴尽量优先制作。

  4. 在满足所有限制,\(1\) 号和 \(2\) 号和 \(3\) 号菜肴尽量优先的前提下,\(4\) 号菜肴尽量优先制作。

  5. 以此类推。

例 1:共 \(4\) 道菜肴,两条限制 \((3,1)\)、\((4,1)\),那么制作顺序是 \(3,4,1,2\)。

例 2:共 \(5\) 道菜肴,两条限制 \((5,2)\)、\((4,3)\),那么制作顺序是 \(1,5,2,4,3\)。

例 1 里,首先考虑 \(1\),因为有限制 \((3,1)\) 和 \((4,1)\),所以只有制作完 \(3\) 和 \(4\) 后才能制作 \(1\),而根据 3,\(3\) 号又应尽量比 \(4\) 号优先,所以当前可确定前三道菜的制作顺序是 \(3,4,1\);接下来考虑 \(2\),确定最终的制作顺序是 \(3,4,1,2\)。

例 \(2\) 里,首先制作 \(1\) 是不违背限制的;接下来考虑 \(2\) 时有 \((5,2)\) 的限制,所以接下来先制作 \(5\) 再制作 \(2\);接下来考虑 \(3\) 时有 \((4,3)\) 的限制,所以接下来先制作 \(4\) 再制作 \(3\),从而最终的顺序是 \(1,5,2,4,3\)。现在你需要求出这个最优的菜肴制作顺序。无解输出 Impossible!(首字母大写,其余字母小写)

分析

如果将做菜变成一个有向无环图(DAG),那么Impossible!的情况就是出现了闭环,不是DAG了。

那剩下的呢?用拓扑排序,怎么拓扑呢?设编号小的菜为 \(a\),编号大的菜为 \(b\)。我们想要 \(a\) 尽量往前靠,可贪心很容易举出反例,这样做不好。那么换种方向,我们让 \(b\) 尽量往后靠,不论\(b\) 具体在哪,我们都保证 \(a\) 在前面,因此就需要反向跑拓扑。让 \(b\) 连向 \(a\),跑反图的拓扑。

参考代码

#include<bits/stdc++.h>
#define cclear(x) memset((x),0,sizeof((x)))
#define final const
using namespace std;

const int MAXN = (1e5+5);
int n,m,cnt;
int indeg[MAXN],ans[MAXN];
vector<int> edge[MAXN];

inline void toposort(){
	priority_queue<int> pq;
	//大根堆的初始化 
	for(int i=1;i<=n;i++){
		if(!indeg[i]){
			pq.push(i);
		}
	}
	while(!pq.empty()){
		final int tmp=pq.top();
		pq.pop();
		ans[++cnt]=tmp;
		for(int it:edge[tmp]){
			indeg[it]--;
			if(!indeg[it]){
				pq.push(it);
			}
		}
	}
}

int main(){
	int t;
	cin>>t;
	while(t--){
		// 清除残余的数据 
		cnt=0;
		cclear(ans);
		cclear(indeg);
		for(int i=1;i<=n;i++){
			edge[i].clear();
		}
		cin>>n>>m;
		for(int i=1,x,y;i<=m;i++){
			cin>>x>>y;
			edge[y].push_back(x); // 反向建图
			indeg[x]++; 
		}
		// 跑一遍拓扑排序
		toposort(); 
		if(cnt<n){
			cout<<"Impossible!";
		}
		else{
			for(int i=n;i>=1;i--){
				// 反向建图当然要倒序输出
				cout<<ans[i]<<' '; 
			}
		}
		cout<<endl;
	}
	return 0;
}

鸣谢

参考资料:

标签:菜肴,顺序,限制,int,HNOI2015,P3243,尽量,制作
来源: https://www.cnblogs.com/xiezheyuan/p/15846560.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有