1. 程式人生 > >[Luogu P3243] [BZOJ 4010] [HNOI2015]菜餚製作

[Luogu P3243] [BZOJ 4010] [HNOI2015]菜餚製作

洛谷傳送門

BZOJ傳送門

題目描述

知名美食家小 A被邀請至ATM 大酒店,為其品評菜餚。 ATM 酒店為小 A A 準備了 N N 道菜餚,酒店按照為菜餚預估的質量從高到低給予1到N的順序編號,預估質量最高的菜餚編號為 1

1

由於菜餚之間口味搭配的問題,某些菜餚必須在另一些菜餚之前製作,具體的,一共有 M M 條形如” i i 號菜餚’必須’先於 j

j 號菜餚製作“的限制,我們將這樣的限制簡寫為 < i , j > <i,j>

現在,酒店希望能求出一個最優的菜餚的製作順序,使得小 A A 能儘量先吃到質量高的菜餚:

也就是說,

(1)在滿足所有限制的前提下, 1 1 號菜餚”儘量“優先製作;

(2)在滿足所有限制, 1 1 號菜餚”儘量“優先製作的前提下, 2 2 號菜餚”儘量“優先製作;

(3)在滿足所有限制, 1 1 號和 2 2 號菜餚”儘量“優先的前提下, 3 3 號菜餚”儘量“優先製作;

(4)在滿足所有限制, 1 1 號和 2 2 號和 3 3 號菜餚”儘量“優先的前提下, 4 4 號菜餚”儘量“優先製作;

(5)以此類推。

例1:共 4 4 道菜餚,兩條限制 < 3 , 1 > < 4 , 1 > <3,1>、<4,1> ,那麼製作順序是 3 , 4 , 1 , 2 3,4,1,2

例2:共 5 5 道菜餚,兩條限制 < 5 , 2 > < 4 , 3 > <5,2>、 <4,3> ,那麼製作順序是 1 , 5 , 2 , 4 , 3 1,5,2,4,3

例1裡,首先考慮 1 1 ,因為有限制 < 3 , 1 > <3,1> < 4 , 1 > <4,1> ,所以只有製作完 3 3 4 4 後才能製作 1 1 ,而根據 ( 3 ) (3) 3 3 號又應”儘量“比 4 4 號優先,所以當前可確定前三道菜的製作順序是 3 , 4 , 1 3,4,1 ;接下來考慮 2 2 ,確定最終的製作順序是 3 , 4 , 1 , 2 3,4,1,2

例 2裡,首先製作 1 1 是不違背限制的;接下來考慮 2 2 時有 < 5 , 2 > <5,2> 的限制,所以接下來先製作 5 5 再製作 2 2 ;接下來考慮 3 3 時有 < 4 , 3 > <4,3> 的限制,所以接下來先製作 4 4 再製作 3 3 ,從而最終的順序是 1 , 5 , 2 , 4 , 3 1,5,2,4,3 。 現在你需要求出這個最優的菜餚製作順序。無解輸出”Impossible!“ (不含引號,首字母大寫,其餘字母小寫)

輸入輸出格式

輸入格式:

第一行是一個正整數 D D ,表示資料組數。 接下來是 D D 組資料。 對於每組資料: 第一行兩個用空格分開的正整數 N N M M ,分別表示菜餚數目和製作順序限制的條目數。 接下來 M M 行,每行兩個正整數 x , y x,y ,表示” x x 號菜餚必須先於y號菜餚製作“的限制。(注意:M條限制中可能存在完全相同的限制)

輸出格式:

輸出檔案僅包含 D D 行,每行 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 先於菜餚 2 2 製作,菜餚 2 2 先於菜餚 3 3 製作,菜餚 3 3 先於菜餚 1 1 製作,而這是無論如何也不可能滿足的,從而導致無解。

100%的資料滿足 N , M 100000 , D 3 N,M\le 100000,D\le 3

解題分析

題目想方設法讓我們相信這是個讓我們按拓撲序和字典序排列的, 然而這樣過不了第三個樣例…

因為我們這樣搞是貪心讓字典序小的放在前面, 然而我們要的是儘量把最小的放在儘量前面, 這樣顯然是 W A 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("");
        }
    }
}