JZOJ 5445 字典序 題解

2021-08-14 05:24:06 字數 1602 閱讀 3749

description

你需要構造乙個1~n的排列,使得它滿足m個條件,每個條件形如(ai,bi),表示ai必須在bi前面。在此基礎上,你需要使它的字典序最小。

input

第一行兩個正整數n,m。接下來m行每行兩個數ai,bi。

output

輸出一行n個整數表示答案。如果不存在這樣的排列,輸出-1。

sample input

5 4

5 4

5 3

4 2

3 2sample output

1 5 3 4 2

data constraint

對於20%的資料,n,m<=10。

對於40%的資料,n,m<=200。

對於60%的資料,n,m<=1000。

對於100%的資料,n,m<=100000。

嘗試建圖。把n當作點的數量,m為邊的數量,顯然對於每乙個(ai, bi)就是從a向b連一條有向邊,滿足所有(ai, bi)的排列即為該dag的拓撲序,因為拓撲序中必定保證乙個點出現時,其前驅節點全部已經出現過,也就實現了題目所給要求。

但是拓撲序是不只有乙個的,題目給定要求尋找字典序最小的排列。

考慮乙個拓撲序,若要使其字典序最小,可以貪心使得編號最小的節點優先計入拓撲序,但是這樣是否會破壞拓撲序的性質呢?在一般的拓撲序中,我們用乙個棧來儲存現在入度為0的節點,這些點按照他們存進棧的次序倒序計入拓撲序,我們可以控制這個過程,使得出棧的點編號為最小的,因為此時棧中每個節點入度都為0,因此這時候無論取出哪個節點加入拓撲序都不會破壞其性質,於是我們就可以選擇編號最小的節點加入拓撲序了。

由於這個棧已經不注重先後順序,只看編號大小,我們可以將其替換為優先佇列,以優先佇列作為容器進行訪問。

一定要理解,拓撲序中的棧僅是乙個容器,棧中元素出棧順序是任意的!因此才會有多個排列。

**:

#include //使用stl優先佇列需要標頭檔案queue

#include

#include

#include

using

namespace

std;

const

int n = 100007, m = 100007; //預留空間以防re

int n, m, u, v, tot = 0;

int to[m], nx[m], st[n], rd[n], vis[n], ans[n];

priority_queue, greater > q; //greater使得每次取出的值是最小的,如果是priority_queue則每次取出的值為最大的,注意greater的後面需要空格,某些編譯器會將其當作》處理導致編譯失敗

void init()

for (int i = 1; i <= n; i++)

if (!rd[i]) //入度為0的節點

}void solve()}}

}if (tot < n) //有一部分節點無法排序

printf("-1\n"); //不存在如此的拓撲序

else

//存在

}int main()

1 2 字典序問題

問題描述 在資料加密和資料壓縮中常需要對特殊的字串進行編碼。給定的字母表 a 由 26 個小 寫英文本母組成 a 該字母表產生的公升序字串是指字串中字母按照從左到 右出現的次序與字母在字母表 現的次序相同,且每個字元最多出現 1 次。例如,a,b,ab,bc,xyz 等字串都是公升序字串。現在對字母...

演算法筆記 01 字典序問題

問題描述 在資料加密和資料壓縮中常需要對特殊的字串進行編碼。給定的字母表a由26 個小寫英文本母組成a 該字母表產生的公升序字串是指字串中字母按照從左到右出現的次序與字母在字母表中出現的次序相同,且每個字元最多出現1次。例如,a,b,ab,bc,xyz 等字串都是公升序字串。現在對字母表a 產生的所...

UVa11520字典序迴圈

本題思路比較簡單,由於要求字典序最小,因此從第乙個位置開始,每次從a開始試錯,如果可以滿足,則進行下一位。我使用了int型別進行儲存,事實證明比標準ac麻煩了。雖然很多時候字串要轉換為int型別便於處理,但這裡不需要,直接把每行當成乙個字串就夠了。類似於ac標準答案,我們可以定義乙個template...