洛谷 P3243 [HNOI2015]菜肴制作(反向建边&&拓扑排序)

题目链接:https://www.luogu.com.cn/problem/P3243

因为对于每一个<x,y>,x一定要在y之前做,所以考虑要让y小的在前面,即在合法范围内让后面的y尽可能大,也就是反序列字典序最大的情况。

所以反向建边,跑一边拓扑排序,并用大根堆替换队列(因为要字典序最大)。并且要考虑无解情况:即所求的拓扑序列与总个数n不相等,即无解。

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<queue>
 4 #include<cstring>
 5 using namespace std;
 6 const int N=100005;
 7 priority_queue<int> q;
 8 int n,m,tot,cnt;
 9 struct node{
10     int to,next;
11 }edge[N];
12 int head[N],in[N],ans[N];
13 void init(){
14     memset(head,-1,sizeof(head));
15     memset(in,0,sizeof(in));
16     memset(ans,0,sizeof(ans));
17     memset(edge,0,sizeof(edge));
18     tot=cnt=0;
19     while(!q.empty()) q.pop();
20 }
21 void add(int u,int v){
22     edge[tot].to=v;
23     edge[tot].next=head[u];
24     head[u]=tot++;
25 }
26 void toposort(){
27     for(int i=1;i<=n;i++){
28         if(in[i]==0) q.push(i);
29     }
30     while(!q.empty()){
31         int u=q.top();q.pop();
32         ans[++cnt]=u;
33         for(int i=head[u];i!=-1;i=edge[i].next){
34             int v=edge[i].to;
35             in[v]--;
36             if(in[v]==0) q.push(v);
37         }
38     }
39 }
40 int main(){
41     int D;
42     scanf("%d",&D); 
43     while(D--){
44         init();
45         scanf("%d%d",&n,&m);
46         for(int i=1;i<=m;i++){
47             int x,y;
48             scanf("%d%d",&x,&y);
49             add(y,x);
50             in[x]++;
51         }
52         toposort();
53         if(cnt!=n) { printf("Impossible!
"); continue;}
54         for(int i=n;i>=1;i--) printf("%d ",ans[i]);
55         printf("
");
56     }
57     return 0;
58 }
AC代码
原文地址:https://www.cnblogs.com/New-ljx/p/13252019.html