[Luogu P3243] [BZOJ 4010] [HNOI2015]菜肴制作

洛谷传送门
BZOJ传送门

题目描述

知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴。 ATM 酒店为小 A A A 准备了 N N N 道菜肴,酒店按照为菜肴预估的质量从高到低给予1到N的顺序编号,预估质量最高的菜肴编号为 1 1 1

由于菜肴之间口味搭配的问题,某些菜肴必须在另一些菜肴之前制作,具体的,一共有 M M M 条形如” i i i 号菜肴’必须’先于 j j j 号菜肴制作“的限制,我们将这样的限制简写为 &lt; i , j &gt; &lt;i,j&gt; <i,j>

现在,酒店希望能求出一个最优的菜肴的制作顺序,使得小 A A A能尽量先吃到质量高的菜肴:

也就是说,

(1)在满足所有限制的前提下, 1 1 1 号菜肴”尽量“优先制作;

(2)在满足所有限制, 1 1 1号菜肴”尽量“优先制作的前提下, 2 2 2号菜肴”尽量“优先制作;

(3)在满足所有限制, 1 1 1号和 2 2 2号菜肴”尽量“优先的前提下, 3 3 3号菜肴”尽量“优先制作;

(4)在满足所有限制, 1 1 1 号和 2 2 2 号和 3 3 3 号菜肴”尽量“优先的前提下, 4 4 4 号菜肴”尽量“优先制作;

(5)以此类推。

例1:共 4 4 4 道菜肴,两条限制 &lt; 3 , 1 &gt; 、 &lt; 4 , 1 &gt; &lt;3,1&gt;、&lt;4,1&gt; <3,1><4,1>,那么制作顺序是 3 , 4 , 1 , 2 3,4,1,2 3,4,1,2

例2:共 5 5 5 道菜肴,两条限制 &lt; 5 , 2 &gt; 、 &lt; 4 , 3 &gt; &lt;5,2&gt;、 &lt;4,3&gt; <5,2><4,3>,那么制作顺序是 1 , 5 , 2 , 4 , 3 1,5,2,4,3 1,5,2,4,3

例1里,首先考虑 1 1 1,因为有限制 &lt; 3 , 1 &gt; &lt;3,1&gt; <3,1> &lt; 4 , 1 &gt; &lt;4,1&gt; <4,1>,所以只有制作完 3 3 3 4 4 4 后才能制作 1 1 1,而根据 ( 3 ) (3) (3) 3 3 3 号又应”尽量“比 4 4 4 号优先,所以当前可确定前三道菜的制作顺序是 3 , 4 , 1 3,4,1 3,4,1;接下来考虑 2 2 2,确定最终的制作顺序是 3 , 4 , 1 , 2 3,4,1,2 3,4,1,2

例 2里,首先制作 1 1 1 是不违背限制的;接下来考虑 2 2 2 时有 &lt; 5 , 2 &gt; &lt;5,2&gt; <5,2>的限制,所以接下来先制作 5 5 5 再制作 2 2 2;接下来考虑 3 3 3 时有 &lt; 4 , 3 &gt; &lt;4,3&gt; <4,3>的限制,所以接下来先制作 4 4 4 再制作 3 3 3,从而最终的顺序是 1 , 5 , 2 , 4 , 3 1,5,2,4,3 1,5,2,4,3。 现在你需要求出这个最优的菜肴制作顺序。无解输出”Impossible!“ (不含引号,首字母大写,其余字母小写)

输入输出格式

输入格式:

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

输出格式:

输出文件仅包含 D D D 行,每行 N N N 个整数,表示最优的菜肴制作顺序,或者“Impossible!“表示无解(不含引号)。

输入输出样例

输入样例#1:
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:
1 5 3 4 2 
Impossible! 
1 5 2 4 3

说明

【样例解释】

第二组数据同时要求菜肴 1 1 1先于菜肴 2 2 2制作,菜肴 2 2 2先于菜肴 3 3 3制作,菜肴 3 3 3先于菜肴 1 1 1制作,而这是无论如何也不可能满足的,从而导致无解。

100%的数据满足 N , M ≤ 100000 , D ≤ 3 N,M\le 100000,D\le 3 N,M100000,D3

解题分析

题目想方设法让我们相信这是个让我们按拓扑序和字典序排列的, 然而这样过不了第三个样例…

因为我们这样搞是贪心让字典序小的放在前面, 然而我们要的是尽量把最小的放在尽量前面, 这样显然是 W A WA WA的。

那么我们反过来考虑, 要尽量把最小的放在尽量前面, 就是尽量把最大的放在后面,就是倒过来做一遍使得其字典序最大的解, 然后反向输出就好了。

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100500
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc);
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
}
int n, m;
std::vector <int> nex[MX];
std::priority_queue <int> pq;
int deg[MX], res[MX];
IN bool cmp(R int x, R int y) {return x > y;}
int main(void)
{
    int T, a, b, tot, now;
    in(T);
    W (T--)
    {
        in(n), in(m), tot = 0;
        std::memset(deg, 0, sizeof(deg));
        for (R int i = 1; i <= n; ++i) nex[i].clear();
        for (R int i = 1; i <= m; ++i)
        {
            in(a), in(b); deg[a]++;
            nex[b].push_back(a);
        }
        for (R int i = n; i; --i)
        {
            if (!deg[i]) pq.push(i);
            std::sort(nex[i].begin(), nex[i].end(), cmp);
        }
        W (!pq.empty())
        {
            now = pq.top(), pq.pop();
            res[++tot] = now;
            for (auto i : nex[now])
            {
                --deg[i];
                if (!deg[i]) pq.push(i);
            }
        }
        if (tot != n) puts("Impossible!");
        else
        {
            for (R int i = n; i; --i) printf("%d ", res[i]);
            puts("");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值