• BZOJ4010[HNOI2015]菜肴制作


    题目链接

    Description

    知名美食家小 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!” (不含引号,
    首字母大写,其余字母小写) 
    

    Input

    第一行是一个正整数D,表示数据组数。

    接下来是D组数据。
    对于每组数据:
    第一行两个用空格分开的正整数N和M,分别表示菜肴数目和制作顺序限
    制的条目数。
    接下来M行,每行两个正整数x,y,表示“x号菜肴必须先于y号菜肴制作”
    的限制。(注意:M条限制中可能存在完全相同的限制)

    Output

    输出文件仅包含 D 行,每行 N 个整数,表示最优的菜肴制作顺序,或

    者”Impossible!”表示无解(不含引号)。

    Sample Input

    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

    Sample Output

    1 5 3 4 2

    Impossible!

    1 5 2 4 3

    HINT

    【样例解释】
    第二组数据同时要求菜肴1先于菜肴2制作,菜肴2先于菜肴3制作,菜肴3先于

    菜肴1制作,而这是无论如何也不可能满足的,从而导致无解。

    100%的数据满足N,M<=100000,D<=3。

    ...

    这道题思路不是特别的难。我们观察到,菜肴的先后顺序其实是一种拓扑序,如果菜肴i必须在菜肴j前完成,那么我们只需要连一条<i,j>的有向边,再拓扑排序一遍就行了

    但怎么按照题目的要求输出呢?

    这其实可以转化为反向输出反图字典序的拓扑序。这两者其实是等效的:

    反图就是每一对菜肴全都不符合条件的图。
    那么反图的最大字典序肯定会保证全都不符合的条件下,1在尽量最后,在此前提下2尽量在最后...,所以反向输出就符合条件了

    接下来考虑维护每个独立联通块的顺序。可以考虑用优先队列,我们在拓扑序的基础上,按照由大到小的顺序将元素插入队列就行了。最后再反着输出。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=500010;
    int to[maxn],nex[maxn],beg[maxn],e;
    int dgr[maxn],n,ans[maxn],Cnt;
    
    int read(){
    	int Value=0,Base=1;char Ch=getchar();
    	for(;!isdigit(Ch);Ch=getchar())if(Ch=='-')Base=-1;
    	for(;isdigit(Ch);Ch=getchar())Value=Value*10+(Ch^'0');
    	return Value*Base;
    }
    
    void add(int x,int y){
    	to[++e]=y;
    	nex[e]=beg[x];
    	beg[x]=e;dgr[y]++;
    }
    
    priority_queue<int,vector<int>,less<int> >q;
    
    void Top_sort(){
    	for(int i=1;i<=n;i++)
    		if(!dgr[i])q.push(i);
    	while(!q.empty()){
    		int x=q.top();q.pop();
    		ans[++Cnt]=x;
    		for(int i=beg[x];i;i=nex[i]){
    			int y=to[i];
    			if(!(--dgr[y]))q.push(y);
    		}
    	}
    }
    
    void mem(){
    	e=0;Cnt=0;
    	memset(beg,0,sizeof beg);memset(to,0,sizeof to);
    	memset(nex,0,sizeof nex);memset(ans,0,sizeof ans);
    	memset(dgr,0,sizeof dgr);
    }
    
    int main( ){
    	int m,j,k,i;
    #ifndef ONLINE_JUDGE
    	freopen("dictionary.in","r",stdin);
    	freopen("dictionary.out","w",stdout);
    #endif
    	for(int Case=read();Case--;){
    		mem();
    		n=read();m=read();
    		for(i=1;i<=m;i++){
    			int x=read(),y=read();
    			add(y,x);
    		}
    		Top_sort();
    		if(Cnt!=n){
    			printf("Impossible!
    ");
    			continue;
    		}
    		for(i=n;i>=1;i--)
    			printf("%d ",ans[i]);
    		puts("");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    (Java实现) 洛谷 P1106 删数问题
    (Java实现) 洛谷 P1603 斯诺登的密码
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1028 数的计算
    (Java实现) 洛谷 P1553 数字反转(升级版)
    (Java实现) 洛谷 P1051 谁拿了最多奖学金
    (Java实现) 洛谷 P1051 谁拿了最多奖学金
    (Java实现) 洛谷 P1106 删数问题
    目测ZIP的压缩率
  • 原文地址:https://www.cnblogs.com/ABCDXYZnoip/p/7777202.html
Copyright © 2020-2023  润新知