洛谷传送门
BZOJ传送门
题目描述
知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴。 ATM 酒店为小 A A A 准备了 N N N 道菜肴,酒店按照为菜肴预估的质量从高到低给予1到N的顺序编号,预估质量最高的菜肴编号为 1 1 1。
由于菜肴之间口味搭配的问题,某些菜肴必须在另一些菜肴之前制作,具体的,一共有 M M M 条形如” i i i 号菜肴’必须’先于 j j j 号菜肴制作“的限制,我们将这样的限制简写为 < i , j > <i,j> <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 道菜肴,两条限制 < 3 , 1 > 、 < 4 , 1 > <3,1>、<4,1> <3,1>、<4,1>,那么制作顺序是 3 , 4 , 1 , 2 3,4,1,2 3,4,1,2。
例2:共 5 5 5 道菜肴,两条限制 < 5 , 2 > 、 < 4 , 3 > <5,2>、 <4,3> <5,2>、<4,3>,那么制作顺序是 1 , 5 , 2 , 4 , 3 1,5,2,4,3 1,5,2,4,3。
例1里,首先考虑 1 1 1,因为有限制 < 3 , 1 > <3,1> <3,1>和 < 4 , 1 > <4,1> <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 时有 < 5 , 2 > <5,2> <5,2>的限制,所以接下来先制作 5 5 5 再制作 2 2 2;接下来考虑 3 3 3 时有 < 4 , 3 > <4,3> <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,M≤100000,D≤3。
解题分析
题目想方设法让我们相信这是个让我们按拓扑序和字典序排列的, 然而这样过不了第三个样例…
因为我们这样搞是贪心让字典序小的放在前面, 然而我们要的是尽量把最小的放在尽量前面, 这样显然是 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("");
}
}
}