競賽題解 NOIP2018 旅行

2022-04-30 23:21:14 字數 2781 閱讀 3799

坑還得一層一層的填

填到day2t1了洛谷 p5022

(以下copy自洛谷,有刪減/修改 (●ˇ∀ˇ●))

小 y 是乙個愛好旅行的 oier。她來到 x 國,打算將各個城市都玩一遍。

小y了解到, x國的 \(n\) 個城市之間有 \(m\) 條雙向道路。每條雙向道路連線兩個城市。 不存在兩條連線同一對城市的道路,也不存在一條連線乙個城市和它本身的道路。並且, 從任意乙個城市出發,通過這些道路都可以到達任意乙個其他城市。小 y 只能通過這些 道路從乙個城市前往另乙個城市。

小 y 的旅行方案是這樣的:任意選定乙個城市作為起點,然後從起點開始,每次可 以選擇一條與當前城市相連的道路,走向乙個沒有去過的城市,或者沿著第一次訪問該 城市時經過的道路後退到上乙個城市。當小 y 回到起點時,她可以選擇結束這次旅行或 繼續旅行。需要注意的是,小 y 要求在旅行方案中,每個城市都被訪問到。

為了讓自己的旅行更有意義,小 y 決定在每到達乙個新的城市(包括起點)時,將 它的編號記錄下來。她知道這樣會形成乙個長度為 \(n\) 的序列。她希望這個序列的字典序 最小,你能幫幫她嗎? 對於兩個長度均為 \(n\) 的序列 \(a\) 和 \(b\),當且僅當存在乙個正整數 \(x\),滿足以下條件時, 我們說序列 \(a\) 的字典序小於 \(b\)。

對於任意正整數 \(1 ≤ i < x\),序列 \(a\) 的第 \(i\) 個元素 \(a_i\) 和序列 bb 的第 \(i\) 個元素 \(b_i\) 相同。

序列 \(a\) 的第 \(x\) 個元素的值小於序列 \(b\) 的第 \(x\) 個元素的值。

輸入格式:

輸入檔案共 \(m + 1\) 行。第一行包含兩個整數\(n,m(m = n 或 n+1)\),中間用乙個空格分隔。

接下來 m 行,每行包含兩個整數 \(u,v (1 ≤ u,v ≤ n)\) ,表示編號為 \(u\) 和 \(v\) 的城市之 間有一條道路,兩個整數之間用乙個空格分隔。

輸出格式:

輸出檔案包含一行,\(n\) 個整數,表示字典序最小的序列。相鄰兩個整數之間用乙個 空格分隔。

這道題特殊點在於它的邊數 \(m\) 只能為 \(n\) 或 \(n+1\),而且是乙個連通圖,無重邊自環!這就意味著它要麼是一棵樹,要麼是只帶有乙個環的「樹」……這是什麼「樹」?——基環樹(我也是第一次用這個東西qwq)

因為要讓字典序最小,所以肯定是從城市 \(1\) 開始。

首先考慮樹的情況:

貪心的,我們只要讓下一步到達的點盡可能小就可以了,所以對於每乙個點 \(u\) ,將與它相連的點按編號大小排序(即將鄰接表排序),當然也可以直接用 \(set\) 存鄰接表,反正我是這麼幹的。然後按照節點編號大小,走沒有訪問過的編號最小的節點就可以了,最後一定可以把整棵樹遍歷完(非常easy?)

然後就是有乙個環的情況了(考場上一直在想一次dfs \(o(nlog_n)\)

[1]貪心……就沒有想過 \(o(n^2)\) 也能過)。

有乙個環,但是我們最多隻會走 \(n-1\) 條邊(不能重複經過點嘛)……那把這個環拆開——刪除環上的一條邊,不就又變成一棵樹了嗎?(基環樹的一般操作)

顯然我們可以一次dfs找到那乙個環上的所有邊(\(o(n)\)),我們把找到的環的 邊的編號 儲存在 \(cir\) 陣列裡。根據上面的思想,我們可以列舉刪除 \(cir[i]\) ,然後按照之前樹的做法貪心的求出刪除 \(cir[i]\) 的時候的最小答案,對於每次求出的答案取最小值就可以了。

具體怎麼做?先列舉 \(cir[i]\) (\(o(n)\)),將標記 \(del\) 賦值為 \(cir[i]\),然後從節點 1 出發遍歷所有點 (\(o(n)\)),當發現要經過的邊的編號為 \(del\) 時,就 continue,不走該邊。所以總的時間複雜度為 \(o(n^2)\) 。

額……不過stl的詭異常數好像在洛谷上有一點卡常qwq,用set的做法在洛谷上只能開 o2 優化才能過,還是推薦直接將鄰接表排序。

(這裡還是把用set寫的**粘上來)

/*lucky_glass*/

#includeusing namespace std;

const int n=5000;

set< pair< int,int > > lnk[n+5];

int n,m,del;

int ans[n+5],res[n+5]; //ans為最終答案,res為當前貪心得到的答案

bool prefer()

return false;

}int vis[n+5],tag;

void dfs(int u)

}int cir[n+5],beg,ok;

void circle(int u,int pre)

circle(v,u);

if(ok) cir[++cir[0]]=id; //儲存環

if(u==beg) ok=false; //完成整個環的搜尋,結束儲存

}}int main()

if(n==m)

}else

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

printf("%d%c",ans[i],i==n?'\n':' ');

return 0;

}

有什麼沒看懂的可以隨時在 \(lucky\[email protected]\) 郵箱問我 (。・∀・)ノ

這裡的 \(o(log_n)\) 的複雜度**於對鄰接表的排序操作 ↩︎

競賽題解 NOIP2018 賽道修建

額 考試的時候大概猜到正解,但是時間不夠了,不敢寫,就寫了騙分qwq 現在把坑填好了 copy from 洛谷 c 城將要舉辦一系列的賽車比賽。在比賽前,需要在城內修建 m 條賽道。c 城一共有 n 個路口,這些路口編號為 1,2,n 有 n 1 條適合於修建賽道的雙向通行的道路,每條道路連線著兩個...

NOIp 2018 旅行 題解

題目傳送門 題目大意 現在有一棵樹或一張只有乙個環的圖 連通 要求遍歷一遍這個圖,遍歷的順序即為乙個長度為 n nn 的序列,要求字典序最小的序列。假如是一棵樹的話,顯然貪心即可,從 1 11 出發,每次往編號小的走就好了。假如只是多一條邊的話,列舉刪掉那一條邊,然後變成一棵樹來做。因為每次都要往編...

比賽 NOIP2018 旅行

發現 m 只有兩種取值,於是可做了 樹的直接貪心 圖的列舉環上的邊去掉,然後做樹的貪心,搜的時候剪一下枝吧 寫得有點亂 include define ui unsigned int define ll long long define db double define ld long double ...