noi2009變換序列

2021-09-08 13:27:29 字數 2862 閱讀 6154

2023年noi全國競賽

時間限制: 1 s

空間限制: 128000 kb

題目等級 : 大師 master

題解

description

對於n個整數0,1,…,n-1,乙個變換序列t可以將i變成ti,其中:ti∈且ui=1 to n-1 =。任意x,y∈,定義x和y之間的距離d(x,y)=min。給定每個i和ti之間的距離d(i,ti),你需要求出乙個滿足要求的變換序列t。如果有多個滿足條件的序列,輸出其中字典序最小的乙個。

說明:對於兩個變換序列s和t,如果存在p輸入描述 

input description

輸入檔案中的第一行為乙個整數n,表示序列的長度。

接下來的一行為n個整數di,其中:di表示i和ti之間的距離。

輸出描述 

output description

如果至少存在乙個滿足要求的變換序列t,則輸出一行為n個整數,表示你計算得到的字典序最小的t;否則輸出「no answer」(不含引號)。

輸出檔案中相鄰兩個數字之間用乙個空格分開,行末不包含多餘空格。

樣例輸入 

sample input

1 1 2 2 1

樣例輸出 

sample output

1 2 4 0 3

資料範圍及提示 

data size & hint

對於30%的資料,滿足:n<=50;

對於60%的資料,滿足:n<=500;

對於100%的資料,滿足:n<=10000。

分類標籤 tags 點此展開 

大陸地區

noi全國競賽

2023年

我現在簡要述說一下這一題的意思:題目的意思就是給出x對y的對應關係:,現在給出d(x,y)和x,求y,並且要求字典序最小的y。(x這組數是從0到n-1,y這組數屬於0到n-1)

下面分析一下樣例就更加方便理解這個題目了:

xd(x,y)

y1

2

4

0

3

表一樣例輸入中給了n為5,,所以表一第一行x的值也是從0到4。表一的第二行d(x,y)就是輸入資料的x,y的關係。最後需要我們求的就是表一第三行的y的資料。

我們可以看到上表中的(每列)每組x,y,d(x,y)都是滿足關係,比如x=0,d(x,y)=1,y=1這一列,

|x-y|=1,n-|x-y|=4,故d(x,y)=1,所以關係成立,後面的以此類推。

我們在仔細來看一下關係式,發現對於這樣的乙個關係式,我們知道d(x,y)和x,求y的話,y最多有四個值,不過其實仔細拿例項出來分析之後,就發現這四個值是可以變成兩個值的。

看到題目,發現題目是乙個赤裸裸的二分匹配。這個題目可以用匈牙利演算法來做,匈牙利演算法的時間複雜度是o(nm),在這裡是完全ok的。

這個題目還有另外乙個難點,就是要求字典序最小的y,其實求最小的y可以在尋找交錯路(匹配關係)的時候倒序尋找,不過這樣做的時候要注意,在存邊關係的連線表的時候要注意從小往大存,確保從字典序小的邊找起。

因為如果正序查詢,按照匈牙利演算法的演算法規則,那麼一定是找到的字典序最大的那個。

問題:求二分圖最大匹配可以用最大流(maximal flow)或者匈牙利演算法(hungarian algorithm)

總結:其實這個題目就是二分匹配中的匈牙利演算法,套用下匈牙利的模板,再想好怎麼輸出字典序最小的y就ok了。

1 #include2 #include3 #include4 #include5 #include6 #include7 #include8 #include9 #include10

#define maxn 10010

11using

namespace

std;

1213

1415

int graph[maxn][2];//

每個點最多連出2條邊,存邊時保證graph[i][0]

1617

int vis[maxn];//

表示節點是否被訪問

18int match[maxn];//

y集合中的點i與x集合的match[i]匹配

19int ans[maxn];//

用於輸出結果

20int

n;21

22//

用來構建關係,確保字典序小的存在前面

23void addedge(int i,int

ver)

2430

else

if(graph[i][0]>ver)

3135

else graph[i][1]=ver;36}

37//

匈牙利演算法中的尋找交錯路

38bool crosspath(int

ns)3951}

52return

false;53

}54//匈牙利演算法倒敘從每個點找交錯路,確保求出最小字典序y

55int

find()

5665

return

tot;66}

6768

6970

intmain()

7185

if(find()//

未能完全匹配則無解。

8690

//統計答案輸出。

91for(int i=0;ii;

92 printf("

%d",ans[0

]);93

for(int i=1;i"%d"

,ans[i]);

94return0;

95 }

NOI2009 變換序列

讀懂題意後發現這道題最主要是要求出字典序最小的排列,考察了匈牙利演算法的實質。首先對於 d i 的定義,我們可以解出可能的 t i 然後將 i 與 t i 連邊,求最大匹配。如果最大匹配 但是要求字典序最小。第一中方法在我 ac 後翻看題解而寫的。這個程式是根據匈牙利演算法的實質寫的。對於乙個待匹配...

NOI2009 變換序列

51 1 2 2 1 1 2 4 0 3 30 的資料中n 50 60 的資料中n 500 100 的資料中n 10000。二分圖匹配 匈牙利演算法的原理是衝突時替換 不過要求字典序最小,乙個點會連出2條邊,加邊先加入大的,這樣在匹配時就會先匹配小的 不過這是針對於鏈式前向星 然後如果i和j都匹配了...

NOI2009 變換序列

here 簡要題意就是給定乙個排列,每個元素有兩個對應關係,問你是否能將該排列轉換為另乙個排列,並使之字典序最小,如果不考慮字典序的話,這題就是裸的一道求二分圖完美匹配的題,那麼我們該如何考慮字典序呢?我們可以按字典序暴力列舉左邊的點與右邊的哪個點相匹配,再跑二分圖。實際上我們可以不這樣做,二分圖匹...