#反向建边 #拓扑排序
题意
- 有n个菜,m个条件约束条件(a,b),表a必须在b之前
- 除了约束条件外,要保证序号小的的尽可能先做
- 在满足所有限制的前提下,1 号菜肴”尽量“优先制作;
- 在满足所有限制,1号菜肴”尽量“优先制作的前提下,2号菜肴”尽量“优先制作;
- 以此类推。
- 例:共4 道菜肴,两条限制<3,1>、<4,1>,那么制作顺序是 3,4,1,2。
思路
- 正向描述这个拓扑序不好描述,因为每做一个菜都可能影响当前的“最优先做的菜”
- 考虑反向描述
- 先做序号最小的->最后做序号最大的
- 通过反向建边,变为在拓扑序中寻找字典序最大的
代码
#include<bits/stdc++.h>
using namespace std;
struct E{
int t,nxt;
}edge[101010];
int head[101010];
int inc[101010];
int cnt;
int n,m;
void insert(int a,int b){
edge[++cnt].t=b;
edge[cnt].nxt=head[a];
head[a]=cnt;
}
priority_queue<int> q;
int ans[101010];
int cnt1;
bool tuopu(){
while(!q.empty()) q.pop();
for(int i=1;i<=n;i++){
if(inc[i]==0){
q.push(i);
}
}
while(!q.empty()){
int x=q.top();
q.pop();
ans[++cnt1]=x;
for(int i=head[x];i!=-1;i=edge[i].nxt){
inc[edge[i].t]--;
if(inc[edge[i].t]==0){
q.push(edge[i].t);
}
}
}
if(cnt1<n) return false;
else return true;
}
int main(){
int d;
cin >> d;
while(d--){
cnt=cnt1=0;
memset(head,-1,sizeof(head));
memset(inc,0,sizeof(inc));
cin >> n >> m;
for(int i=1;i<=m;i++){
int a,b;
cin >> a >> b;
insert(b,a);
inc[a]++;
}
if(!tuopu()) cout << "Impossible!" << endl;
else{
for(int i=n;i>=1;i--){
cout << ans[i] << ' ';
}
cout << endl;
}
}
}