题目链接:https://www.luogu.org/problem/P3243
题目大意:
就是求上菜的顺序,某些菜肴必须在另一些菜肴之前制作,但需要注意的是题中指出希望小 A能尽量先吃到质量高的菜肴。
题目讨论:
我们这里希望小A能尽量先吃到质量高的菜肴,那就是希望1尽量早出现,然后2再早出现等等等。
如果我们这里直接对i 号菜肴’必须’先于 j 号菜肴制作记作:i -> j,再加一个小顶堆(队头元素最小)的优先队列去拓扑排序---------所得到的答案明显是错误的。因为我们的“策略”错了。
举例:第三种案例:
输入:
5 2
5 2
4 3
输出:
1 5 2 4 3
我们的策略所得到的答案:1 4 3 5 2
很明显我们的优先队列是对整体去得到一个字典序小的顺序
而我们需要的是希望小 A能尽量先吃到质量高的菜肴
小A在吃到1之后,去吃2,而吃2之前限制是需要先吃5,然后去吃3,而吃3之前需要先吃4,所以正确答案是1 5 2 4 3
我们这里的拓扑排序时分别从1到n对每一个数去求前面的限制,所以我们可以转个方向:i 号菜肴’必须’先于 j 号菜肴制作记作:j->i,然后用大顶堆(队头元素最大)的优先队列去存答案,然后再逆序输出就可以得到我们需要的答案。
代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 100010
struct EDGE{
int to,nxt;
}edge[maxn];
int cnt,n,m;
int head[maxn],in[maxn],out[maxn];
int ans[maxn];
void add(int x,int y){
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
head[x]=cnt;
}
priority_queue<int> q;
int tt;
void TuPu(){
for(int i=1;i<=n;i++){
if(!in[i]) {
q.push(i);
}
}
while(!q.empty()){
int v=q.top();
q.pop();
ans[tt++]=v;
for(int i=head[v];i;i=edge[i].nxt){
int u=edge[i].to;
in[u]--;
if(!in[u]) q.push(u);
}
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
while(!q.empty()) q.pop();
memset(head,0,sizeof(head));
memset(ans,0,sizeof(ans));
memset(in,0,sizeof(in));
cnt=0;
int x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(y,x);//相反顺序
in[x]++;out[y]++;
}
tt=1;
TuPu();
if(tt<n-1) printf("Impossible!\n");
else{
for(int i=n;i>1;i--)
cout<<ans[i]<<" ";
cout<<ans[1]<<endl;
}
}
}