zoukankan      html  css  js  c++  java
  • [BZOJ4010]:[HNOI2015]菜肴制作(拓扑排序)

    题目传送门


    题目描述

    知名美食家小A被邀请至ATM大酒店,为其品评菜肴。

    ATM酒店为小A准备了N道菜肴,酒店按照为菜肴预估的质量从高到低给予1N的顺序编号,预估质量最高的菜肴编号为1。由于菜肴之间口味搭配的问题,某些菜肴必须在另一些菜肴之前制作,具体的,一共有M条形如“i号菜肴‘必须’先于j号菜肴制作”的限制,我们将这样的限制简写为<i,j>

    现在,酒店希望能求出一个最优的菜肴的制作顺序,使得小A能尽量先吃到质量高的菜肴:也就是说,
      (1)在满足所有限制的前提下,1号菜肴“尽量”优先制作;
      (2)在满足所有制,1号菜肴“尽量”优先制作的前提下,2号菜肴“尽量”优先制作;
      (3)在满足所有限制,1号和2号菜肴“尽量”优先的前提下,3号菜肴“尽量”优先制作;
      (4)在满足所有制,1号和2号和3号菜肴“尽量”优先的前提下,4号菜肴“尽量”优先制作;
      (5)以此类推。
    例一:共4道菜肴,两条限制<3,1><4,1>,那么制作顺序是3,4,1,2
    例二:共5道菜肴,两条限制<5,2><4,3>,那么制作顺序是1,5,2,4,3
    例一里,首先考虑1,因为有限制<3,1><4,1>,所以只有制作完34后才能制作1,而根据(3)3号又应“尽量”比4号优先,所以当前可确定前三道菜的制作顺序是3,4,1;接下来考虑2,确定最终的制作顺序是3,4,1,2
    例二里,首先制作1是不违背限制的;接下来考虑2时有<5,2>的限制,所以接下来先制作5再制作2;接下来考虑3时有<4,3>的限制,所以接下来先制作4再制作3,从而最终的顺序是1,5,2,4,3
    现在你需要求出这个最优的菜肴制作顺序。无解输出“Impossible!” (不含引号,首字母大写,其余字母小写)。

    输入格式

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

    接下来是D组数据。 
    对于每组数据: 
    第一行两个用空格分开的正整数NM,分别表示菜肴数目和制作顺序限
    制的条目数。 
    接下来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制作,而这是无论如何也不可能满足的,从而导致无解。

    数据范围与提示

    100%的数据满足N,M≤100000D≤3

    题解

    首先,这种题应该都能想到拓扑排序,如果你没想到那我也没法,如果你说不知道什么是拓扑排序,那……
    然后就会想,把拓扑排序里的队列换成小跟堆。
    的确,会有15分。
    那么为什么不对呢?
    因为我们在决策当前先走哪个点的时候并不知道后面会发生什么,而这道题恰恰要求我们只尽可能的让权值小的先输出出来。
    那完了……
    怎么办?考虑这样一个思路,反向建图,用大跟堆,最后反向输出。
    为什么这样就对了呢?因为这样是先走尽可能大的节点,实在不行了才走小的节点,这样就保证了结果的最优性。

    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct rec
    {
    	int nxt;
    	int to;
    }e[100001];
    int n,m;
    int head[100001],cnt;
    int d[100001];
    int ans[100001];
    bool flag;
    priority_queue<int,vector<int>,less<int> > q;//大跟堆
    void add(int x,int y)//建边
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	head[x]=cnt;
    }
    void topsort()//拓扑排序
    {
    	for(int i=n;i;i--)
    		if(!d[i])q.push(i);
    	while(!q.empty())
    	{
    		int flag=q.top();
    		q.pop();
    		ans[++ans[0]]=flag;
    		for(int i=head[flag];i;i=e[i].nxt)
    		{
    			d[e[i].to]--;
    			if(!d[e[i].to])q.push(e[i].to);
    		}
    	}
    	if(ans[0]<n)puts("Impossible!");//如果存在环
    	else
    	{
    		for(int i=ans[0];i;i--)//输出答案
    			printf("%d ",ans[i]);
    		puts("");
    	}
    }
    void pre_work()//多测不清空,爆零两行泪TAT……
    {
    	memset(d,0,sizeof(d));
    	memset(head,0,sizeof(head));
    	cnt=flag=ans[0]=0;
    }
    int main()
    {
    	int D;
    	scanf("%d",&D);
    	while(D--)
    	{
    		pre_work();
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=m;i++)
    		{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			d[x]++;
    			add(y,x);//反向建边
    		}
    		topsort();
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    C#命名约定:PascalCase和camelCase
    Windows8 App 四大名著完整本 隐私保护声明
    C#-编码习惯
    [转]C#之Console.Write()和Console.Read()及Console.Readline()的问题
    通过JavaScript动态输入计算
    在VS2008中加入ExtJS智能提示—>(方法一)
    在VS2008中加入ExtJS智能提示—>(方法二)
    (一)javascript面向对象:(1)类
    上证指数波浪分析2013/03/12
    Springsecurity源码Filter之HeaderWriterFilter(十二)
  • 原文地址:https://www.cnblogs.com/wzc521/p/11170490.html
Copyright © 2011-2022 走看看