[题解]洛谷P3243菜肴制作

[题解]洛谷P3243菜肴制作

原题链

算法:拓扑排序

过程:

首先,一定存在一个菜是不依赖于别的菜的,即不存在一个菜要求在这个菜之前坐,因此我们可以先做这个菜.如果我们将题中的关系转化为一个有向图(,即如果一个菜要在另一个菜之前做,则连一条从先做菜指向后做菜的边)那么我们第一个做的菜一定是入度为0的,但如果这个有向图中存在环,那么很明显,环中的菜是不可能被做出来的,这是输出Impossible.又因为题中给出了在满足条件的情况下编号小的要靠前,但是如果用小根堆来维护则表示位置靠前的标号尽量小,虽然求出的拓扑序字典序是最小的,但是编号小的不一定在前面,举个栗子:存在限制条件:①做4前做2;②做1前做3;如果是字典序最小则答案为:2,3,1,4,但是符合题目要求的却是3,1,2,4;这时我们不妨考虑让越靠后位置的编号越大则可以解决这个问题.因此我们将原图建反图,再用大根堆维护,最后输出时将得到的拓扑序反过来输出即可.

AC代码

#include <bits/stdc++.h>
using namespace std;
struct node{
	int to,next;
}e[100010];
int fir[100010],out_d[100010],ans[100010],num,n,m,tot;
priority_queue < int > heap;
void add(int x,int y){
	e[++tot].to = y;
	e[tot].next = fir[x];
	fir[x] = tot;
}
void T_sort(){
	while(!heap.empty())heap.pop();
	for(int i = 1;i <= n;i++){
		if(out_d[i] == 0)
			heap.push(i);
	}
	while(!heap.empty()){
		int x = heap.top();
		ans[++num] = x;
		heap.pop();
		for(int i = fir[x];i;i = e[i].next){
			out_d[e[i].to]--;
			if(out_d[e[i].to] == 0)
				heap.push(e[i].to);
		}
	}
	return;
}
int main(){
	int D;
	cin>>D;
	while(D){
		D--;
		cin>>n>>m;
		tot = 0;
		memset(out_d,0,sizeof(out_d));
		memset(ans,0,sizeof(ans));
		memset(fir,0,sizeof(fir));
		for(int i = 1;i <= n;i++){e[i].to = e[i].next = 0;}
		num = 0;
		for(int i = 1;i <= m;i++){
			int x,y;
			cin>>x>>y;
			add(y,x);
			out_d[x]++;
		}
		T_sort();
		bool flag = true;
		for(int i = 1;i <= n;i++){
			if(out_d[i] != 0){
				flag = false;
				break;
			}
		}
		if(!flag){
			cout<<"Impossible!"<<endl;
			continue;
		}
		for(int i = num;i >= 1;i--)
			cout<<ans[i]<<" ";
		cout<<endl;
		
	}
	return 0;
}
posted @ 2020-08-22 16:02  czyczy  阅读(118)  评论(1编辑  收藏  举报