[HNOI2015]菜肴制作
[HNOI2015]菜肴制作
时间限制:2 s 内存限制:512 MB
【题目描述】
知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴。
ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予1到N的顺序编号,预估质量最高的菜肴编号为1。由于菜肴之间口味搭配的问题,某些菜肴必须在另一些菜肴之前制作,具体的,一共有 M 条形如“i 号菜肴‘必须’先于 j 号菜肴制作”的限制,我们将这样的限制简写为<i,j>。现在,酒店希望能求出一个最优的菜肴的制作顺序,使得小 A能尽量先吃到质量高的菜肴:也就是说,(1)在满足所有限制的前提下,1 号菜肴“尽量”优先制作;(2)在满足所有限制,1号菜肴“尽量”优先制作的前提下,2号菜肴“尽量”优先制作;(3)在满足所有限制,1号和2号菜肴“尽量”优先的前提下,3号菜肴“尽量”优先制作;(4)在满足所有限制,1 号和 2 号和 3 号菜肴“尽量”优先的前提下,4 号菜肴“尽量”优先制作;(5)以此类推。
例1:共4 道菜肴,两条限制<3,1>、<4,1>,那么制作顺序是 3,4,1,2。例2:共5道菜肴,两条限制<5,2>、 <4,3>,那么制作顺序是 1,5,2,4,3。例1里,首先考虑 1,因为有限制<3,1>和<4,1>,所以只有制作完 3 和 4 后才能制作 1,而根据(3),3 号又应“尽量”比 4 号优先,所以当前可确定前三道菜的制作顺序是 3,4,1;接下来考虑2,确定最终的制作顺序是 3,4,1,2。例 2里,首先制作 1是不违背限制的;接下来考虑 2 时有<5,2>的限制,所以接下来先制作 5 再制作 2;接下来考虑 3 时有<4,3>的限制,所以接下来先制作 4再制作 3,从而最终的顺序是 1,5,2,4,3。
现在你需要求出这个最优的菜肴制作顺序。无解输出“Impossible!” (不含引号,首字母大写,其余字母小写)
【输入格式】
第一行是一个正整数D,表示数据组数。
接下来是D组数据。
对于每组数据:
第一行两个用空格分开的正整数N和M,分别表示菜肴数目和制作顺序限制的条目数。
接下来M行,每行两个正整数x,y,表示“x号菜肴必须先于y号菜肴制作”的限制。(注意:M条限制中可能存在完全相同的限制)
【输出格式】
输出文件仅包含 D 行,每行 N 个整数,表示最优的菜肴制作顺序,或者”Impossible!”表示无解(不含引号)。
【样例输入】
3 5 4 5 4 5 3 4 2 3 2 3 3 1 2 2 3 3 1 5 2 5 2 4 3
【样例输出】
1 5 3 4 2 Impossible! 1 5 2 4 3
【提示】
第二组数据同时要求菜肴1先于菜肴2制作,菜肴2先于菜肴3制作,菜肴3先于菜肴1制作,而这是无论如何也不可能满足的,从而导致无解。
30%的数据满足N,M<=200,D<=3
70%的数据满足N,M<=5000,D<=3
100%的数据满足N,M<=100000,D<=3。
solution:
这题一开始没有想到拓扑排序,后来想到了又没想到倒着来,很懵逼。
正解是反着来的,用大根堆,逆向建边,而最后反向输出!!!如果正着找,可能会忽略后面的更小值,而更小值优先级大于当前较小值,错解。而如果反向找最大,最小的一定找到的较后,而最大值被忽略,但最大值的优先级小于较大值,那么最大值被忽略就是可以的。所以证明反向是对的。(来自大佬qty)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 #define mod 1000000007 8 int read() { 9 int s=0,f=1; 10 char ch=getchar(); 11 while(ch>'9'||ch<'0') { 12 if(ch=='-') { 13 f=-1; 14 } 15 ch=getchar(); 16 } 17 while(ch>='0'&&ch<='9') { 18 s=(s<<1)+(s<<3)+(ch^48); 19 ch=getchar(); 20 } 21 return s*f; 22 } 23 priority_queue<int> q; 24 int D,n,m,tot,r[100005],indexx[100005],ans[100005],ji; 25 bool cut[100005]; 26 struct node { 27 int to,next; 28 } c[200005]; 29 void add(int x,int y) { 30 c[tot]=(node) { 31 y,r[x] 32 }; 33 r[x]=tot++; 34 } 35 void clear() { 36 ji=tot=0; 37 memset(r,-1,sizeof(r)); 38 memset(indexx,0,sizeof(indexx)); 39 memset(cut,false,sizeof(cut)); 40 memset(c,0,sizeof(c)); 41 memset(ans,0,sizeof(ans)); 42 } 43 bool bfs() { 44 while(!q.empty()) { 45 int k=q.top(); 46 q.pop(); 47 ans[++ji]=k; 48 for(int i=r[k]; ~i; i=c[i].next) { 49 --indexx[c[i].to]; 50 if(!indexx[c[i].to]){ 51 q.push(c[i].to); 52 } 53 } 54 } 55 return ji==n; 56 } 57 int Main(){ 58 //freopen("dishes.in","r",stdin); 59 //freopen("dishes.out","w",stdout); 60 D=read(); 61 while(D--) { 62 clear(); 63 n=read(); 64 m=read(); 65 for(int x,y,i=1; i<=m; ++i) { 66 x=read(); 67 y=read(); 68 add(y,x); 69 indexx[x]++; 70 } 71 for(int i=1; i<=n; ++i) { 72 if(!indexx[i]) { 73 q.push(i); 74 } 75 } 76 bool pd=bfs(); 77 if(!pd) { 78 printf("Impossible!\n"); 79 } else { 80 for(int i=ji; i; --i) { 81 printf("%d ",ans[i]); 82 } 83 printf("\n"); 84 } 85 } 86 return 0; 87 88 } 89 int hehe=Main(); 90 int main() { 91 ; 92 }