[题解]洛谷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;
}