[Luogu P3243] [BZOJ 4010] [HNOI2015]菜餚製作
洛谷傳送門
BZOJ傳送門
題目描述
知名美食家小 A被邀請至ATM 大酒店,為其品評菜餚。 ATM 酒店為小 準備了 道菜餚,酒店按照為菜餚預估的質量從高到低給予1到N的順序編號,預估質量最高的菜餚編號為 。
由於菜餚之間口味搭配的問題,某些菜餚必須在另一些菜餚之前製作,具體的,一共有 條形如” 號菜餚’必須’先於 號菜餚製作“的限制,我們將這樣的限制簡寫為 。
現在,酒店希望能求出一個最優的菜餚的製作順序,使得小 能儘量先吃到質量高的菜餚:
也就是說,
(1)在滿足所有限制的前提下, 號菜餚”儘量“優先製作;
(2)在滿足所有限制, 號菜餚”儘量“優先製作的前提下, 號菜餚”儘量“優先製作;
(3)在滿足所有限制, 號和 號菜餚”儘量“優先的前提下, 號菜餚”儘量“優先製作;
(4)在滿足所有限制, 號和 號和 號菜餚”儘量“優先的前提下, 號菜餚”儘量“優先製作;
(5)以此類推。
例1:共 道菜餚,兩條限制 ,那麼製作順序是 。
例2:共 道菜餚,兩條限制 ,那麼製作順序是 。
例1裡,首先考慮 ,因為有限制 和 ,所以只有製作完 和 後才能製作 ,而根據 , 號又應”儘量“比 號優先,所以當前可確定前三道菜的製作順序是 ;接下來考慮 ,確定最終的製作順序是 。
例 2裡,首先製作 是不違背限制的;接下來考慮 時有 的限制,所以接下來先製作 再製作 ;接下來考慮 時有 的限制,所以接下來先製作 再製作 ,從而最終的順序是 。 現在你需要求出這個最優的菜餚製作順序。無解輸出”Impossible!“ (不含引號,首字母大寫,其餘字母小寫)
輸入輸出格式
輸入格式:
第一行是一個正整數 ,表示資料組數。 接下來是 組資料。 對於每組資料: 第一行兩個用空格分開的正整數 和 ,分別表示菜餚數目和製作順序限制的條目數。 接下來 行,每行兩個正整數 ,表示” 號菜餚必須先於y號菜餚製作“的限制。(注意:M條限制中可能存在完全相同的限制)
輸出格式:
輸出檔案僅包含 行,每行 個整數,表示最優的菜餚製作順序,或者“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
說明
【樣例解釋】
第二組資料同時要求菜餚 先於菜餚 製作,菜餚 先於菜餚 製作,菜餚 先於菜餚 製作,而這是無論如何也不可能滿足的,從而導致無解。
100%的資料滿足 。
解題分析
題目想方設法讓我們相信這是個讓我們按拓撲序和字典序排列的, 然而這樣過不了第三個樣例…
因為我們這樣搞是貪心讓字典序小的放在前面, 然而我們要的是儘量把最小的放在儘量前面, 這樣顯然是 的。
那麼我們反過來考慮, 要儘量把最小的放在儘量前面, 就是儘量把最大的放在後面,就是倒過來做一遍使得其字典序最大的解, 然後反向輸出就好了。
程式碼如下:
#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("");
}
}
}