问题描述

知名美食家小 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制作,而这是无论如何也不可能满足的,从而导致无解。

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

解析

一个直观的想法是拓扑排序,为了满足要求会想到求字典序最小的拓扑序。但是,有可能会出现样例3那样,满足了字典序最小却没有做到小的尽可能要求。为了避免后效性,我们可以建反图再跑字典序最大的拓扑排序,就可以做到答案正确。

代码

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define N 100002
using namespace std;
int head[N],ver[N],nxt[N],d[N],l;
int t,n,m,i,ans[N],cnt;
int read()
{
char c=getchar();
int w=0;
while(c<'0'||c>'9') c=getchar();
while(c<='9'&&c>='0'){
w=w*10+c-'0';
c=getchar();
}
return w;
}
void insert(int x,int y)
{
l++;
ver[l]=y;
nxt[l]=head[x];
head[x]=l;
d[y]++;
}
void toposort()
{
priority_queue<int> q;
for(int i=1;i<=n;i++){
if(d[i]==0) q.push(i);
}
while(!q.empty()){
int x=q.top();
q.pop();
ans[++cnt]=x;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
d[y]--;
if(d[y]==0) q.push(y);
}
}
}
int main()
{
t=read();
while(t--){
cnt=l=0;
memset(head,0,sizeof(head));
memset(d,0,sizeof(d));
n=read();m=read();
for(i=1;i<=m;i++){
int u=read(),v=read();
insert(v,u);
}
toposort();
if(cnt<n) printf("Impossible!\n");
else{
for(i=n;i>=1;i--) printf("%d ",ans[i]);
puts("");
}
}
}

[洛谷P3243] 菜肴制作的更多相关文章

  1. Luogu P3243 菜肴制作

    Luogu P3243 菜肴制作 神神奇奇的拓扑排序,也就是借这道题学习一下大名鼎鼎的Toposort了-- #include<bits/stdc++.h> #define N 10001 ...

  2. 洛谷P3243 [HNOI2015]菜肴制作——拓扑排序

    题目:https://www.luogu.org/problemnew/show/P3243 正向按字典序拓扑排序很容易发现是不对的,因为并不是序号小的一定先做: 但若让序号大的尽可能放在后面,则不会 ...

  3. 洛谷P3243 [HNOI2015]菜肴制作 拓扑排序+贪心

    正解:拓扑排序 解题报告: 传送门! 首先看到它这个约束就应该要想到拓扑排序辣QwQ 首先想到的应该是用优先队列代替队列,按照节点编号排序 然后也很容易被hack:<5,1> 正解应为5, ...

  4. 洛谷 P3243 [HNOI2015]菜肴制作 题解

    每日一题 day60 打卡 Analysis 这道题一看就感觉是个拓扑排序,但因为按字典序最小的排序会有问题(见第三个样例)主要原因是每次选择有后效性,而从后往前就不会存在这个问题,因为每个子任务都是 ...

  5. 洛谷 P3243 【[HNOI2015]菜肴制作】

    先吐槽一下这个难度吧,评的有点高了,但是希望别降,毕竟这是我能做出来的不多的紫题了(狗头). 大家上来的第一反应应该都是啊,模板题,然后兴高采烈的打了拓补排序的板子,然后搞个小根堆,按照字典序输出就可 ...

  6. 洛谷P3243 [HNOI2015]菜肴制作 (拓扑排序/贪心)

    这道题的贪心思路可真是很难证明啊...... 对于<i,j>的限制(i必须在j之前),容易想到topsort,每次在入度为0的点中选取最小的.但这种正向找是错误的,题目要求的是小的节点尽量 ...

  7. 洛谷 P6775 - [NOI2020] 制作菜品(找性质+bitset 优化 dp)

    题面传送门 好久没写过题解了,感觉几天没写手都生疏了 首先这种题目直接做肯定是有些困难的,不过注意到题目中有个奇奇怪怪的条件叫 \(m\ge n-2\),我们不妨从此入手解决这道题. 我们先来探究 \ ...

  8. 洛谷P1169 棋盘制作(悬线法)

    题目链接:https://www.luogu.org/problemnew/show/P1169 #include<bits/stdc++.h> #define fi first #def ...

  9. 洛谷P1169 棋盘制作【悬线法】【区间dp】

    题目:https://www.luogu.org/problemnew/show/P1169 题意:n*m的黑白格子,找到面积最大的黑白相间的正方形和矩形. 思路:传说中的悬线法!用下面这张图说明一下 ...

随机推荐

  1. Kolla 让 OpenStack 部署更贴心

    目录 目录 Kolla 简介 Kolla & Kolla-ansible 部署 OpenStack 准备操作系统基础环境 准备 Python 基础环境 准备 Docker 基础环境 安装 ko ...

  2. kafka多线程消费

    建立kafka消费类ConsumerRunnable ,实现Runnable接口: import com.alibaba.fastjson.JSON; import com.alibaba.fastj ...

  3. ES6标准入门 第五章:函数的扩展

    1.函数参数的默认值 (1)基本用法 ES5 中, 不能直接为函数的参数指定默认值.只能采用变通的方法. function log(x, y) { y = y || 'World'; console. ...

  4. echars 柱状图 堆叠状态 --》二次封装

    <template> <!-- 柱状图 堆叠 1. 调用页面引入 import EcharsColumnStack from '@/components/echarsColumnSt ...

  5. Canvas入门07- 自定义实现虚线的绘制

    预备知识 直线的斜率 一条直线与某平面直角坐标系x轴正半轴方向的夹角的正切值即该直线相对于该坐标系的斜率. 对于一条直线 y = kx +b,k就是直线的斜率. 斜率的计算 对于一条已知的线段,求斜率 ...

  6. django中使用原生的orm

    只有用的时候才能执行

  7. 【转】centos7安装

    转自:https://blog.csdn.net/qq_42570879/article/details/82853708 1.CentOS下载CentOS是免费版,推荐在官网上直接下载,网址:htt ...

  8. linux服务器上安装mysql

    mysql版本:mysql-5.6.44-linux-glibc2.12-x86_64.tar linux操作系统和版本信息: 1.检查linux服务器上是否已安全mysql [root@localh ...

  9. C++中的深拷贝和浅拷贝构造函数

    1,对象的构造在实际工程开发当中是相当重要的,C++ 中使用类就要创建对象,这 就涉及了对象的构造,本节课讲解对象的构造和内存操作方面的问题: 2,实际工程开发中,bug 产生的根源,必然的会有内存操 ...

  10. 工作日记之查看Linux系统里面的启动频率2017_02_07

    链接:http://www.jb51.net/LINUXjishu/19905.html 查看Linux里面的batch: cat /etc/crontab (1)0 19 * * 6 root /d ...