WC前的頹廢 帶花樹

2022-05-16 02:59:27 字數 3337 閱讀 2106

qaq現在很不想寫題解部落格那就來寫個演算法吧qaq...

題目來看個題...

uoj79.

某機房裡有\(n\)個oier,其中有\(n\)個男生,\(0\)個女生。現在他們要兩兩配對。

有\(m\)個關係,每個關係是乙個無序對\((a_i,b_i)\),表示這兩個人之間願意配對。

求:最多能配成多少對,並找出一組方案。

說人話:一般圖最大匹配。

演算法既然是匹配,我們能不能直接模仿匈牙利演算法呢?答案是不可以(廢話,可以的話還要什麼帶花樹啊)。

原因是:我們在二分圖中,如果dfs找增廣路時經過某個點找不到,那麼我們可以證明這一輪中這個點的確是無用的(也即,這一輪裡所有的增廣路都不經過這個點),於是我們就能保證每個點至多走一遍,時間複雜度得到保證。

但是如果是一般圖,這個性質不一般成立。比如下圖:

圖中紅線是已匹配的邊。那麼,如果我從\(1\)開始dfs時先經過\(2\),那麼接下來就只能到\(4\)(因為只能走匹配邊),然後是\(5,3\),同時我們會給這四個節點都打乙個「找不到增廣路」的標記。

但是實際上存在\(1\rightarrow3\rightarrow5\rightarrow4\rightarrow2\rightarrow6\)這條增廣路。仔細觀察我們就能發現:這種現象之所以存在,是由於奇環\(1-3-5-4-2-1\)的存在(如果沒有奇環,就變成了二分圖匹配,這時候匈牙利演算法就是對的)。

那麼,對於奇環,有什麼後果呢?顯然,如果我們dfs出了乙個奇環,那麼無論環上那個點dfs出了增廣路都是可行的。(例如,上圖中,如果從\(5\)處dfs出一條增廣路,使得\(5\)匹配到別的點且\(3\)成為未蓋點,那麼可以走\(1-3\)。同樣,如果\(5\)被孤立,我們可以走\(1-2-4-5\)來把\(5\)匹配上)

於是,我們可以把乙個奇環當做乙個點(這個奇環被稱為「花」,這就是帶花樹名字的來歷),然後繼續找增廣路。

形式化的,如果我們在圖\(g=(v,e)\)中找到了乙個奇環\(v_1-v_2-\dots-v_k-v_1\)(稱為「花」),其中\(v_1\)是環上的深度最小的結點,不難證明,\(v_1\)的配偶不在此話中(因為在找到這個花之前所有邊組成乙個二分圖,那麼由於\(v_1\)向下dfs/bfs出了乙個花,它一定是x結點,只有x結點會向外擴充套件),且\((v_2,v_3),(v_4,v_5)\dots(v_,v_)\)都是匹配邊。那麼我們構建乙個圖

\[\beging'&=(v', e'),\\ v'&=v/\,\\ e'&=\\end

\]其中\(f(v_i)=v_1, f(a)=a(a\neq v_j), i, j=1,2,\dots,k\)

並且原本\(g\)中的所有匹配除掉\((v_2,v_3),(v_4,v_5)\dots(v_,v_)\)構成\(g'\)的乙個匹配。

那麼,\(g\)中存在增廣路\(\leftrightarrow\)

\(g'\)中存在增廣路。

證明:\(\rightarrow\):對於\(g\)中的任意一條增廣路,若其不經過這朵花,那麼在\(g'\)中也存在這條增廣路;否則,令這條從\(s\)開始的增廣路上的最後乙個在花上的點為\(v_j\),那麼這條增廣路形如 \(s\leadsto v_j \leadsto t\),我們在\(g'\)上構造如下增廣路:先從\(s \leadsto v_1 \leadsto t\),其中第一段路程沿著bfs/dfs樹走,第二段路程沿著原圖中的增廣路走,唯一不同的是\(v_j\)變成了\(v_1\)(這是合法的,因為所有從\(v_j\)出發的邊都被連到了\(v_1\)上,而且我們根據所有\(v\)都是已蓋點可以知道\(v_j\)出發的邊是非匹配邊)。

\(\leftarrow\):對於\(g'\)中的一條增廣路,若它不經過\(v_1\),則\(g\)中也存在;否則,設這條增廣路為\(s\leadsto v_1\rightarrow x \leadsto t\)(\(x\)可能等於\(t\)),根據\(e'\)的定義存在\((v_i, x)\in e\),從而我們構造\(g\)中的增廣路:\(s\leadsto v_1\leadsto v_i \rightarrow x \leadsto t\),其中第一段和第三段不變(因為增廣路上\(v_1\)至多出現1次,所以這兩段在\(g\)中存在),第二段是在花裡走(或者精確一點,若\(i\)是奇數,走\(v_1\rightarrow v_2 \dots v_i\),否則走\(v_1\rightarrow v_k \dots v_i\)。證畢。

bfs時,我們可以\(o(n)\)求出lca並\(o(kn)\)縮花,從而單次bfs至多\(o(n^2)\),總複雜度至多\(o(n^3)\)。

實現上,我們不實際縮點,而是對於每個點維護乙個\(fa\),表示它所處的最大的花的lca(就是\(v_1\))。由於花裡可能還有花,這個\(fa\)要用並查集維護。在證明中構造增廣路是通過判斷\(i\)奇偶性,但實際上我們可以直接維護每個點要往哪邊走,也即維護乙個\(link_i\)表示如果\(i\)失配要和誰匹配(例如,\(link_=v_1,link_=v_4\))。找lca的時候直接暴力\(o(n)\),但要注意只找每個並查集的根節點(因為非根節點都縮到花裡了);縮花時要注意如果兩個點已經在一朵花裡就不要再縮了。

**

#include #include const int n = 550;

const int m = 250050;

int pre[n], nxt[m], to[m], cnt, n;

int vis[n], fa[n], link[n], mate[n];

int que[n], head, tail;

int ss[n], time;

inline void addedge(int x, int y)

int find(int x)

int lca(int x, int y)

std::swap(x, y);

} return x;

}void flower(int x, int y, int p)

}bool match(int x)

return true;

}} else if (vis[u] == 2 && find(u) != find(x))

}} return false;

}int main()

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

if (!mate[i] && match(i))

++ans;

printf("%d\n", ans);

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

printf("%d ", mate[i]);

return 0;

}

頹廢的人做著不頹廢的事

窗外下著大雨,靜靜的看著,點燃一支香菸深深的吸進肺裡,獨飲烈酒,感受著香菸和烈酒的辛辣 好久好久沒有過這樣的文字 剪一段時光,窗前聽雨,雨打屋簷,遍地飛花,長髮遮住了眼,不用去看,這樣的夜晚,就算是晴天,就算豔陽高照,睜著眼,依舊是如同黑夜般 能與何人促膝長談?告訴自己曾經只是一部電影,看過了就結束...

頹廢的生活

又到了一年的10月下旬了,太快了。how time flies 中學作文的常用語,我算是真正 體會到了。2年前的這個時候就想找個哥們喝點酒,抽幾隻煙,可是沒有找到這個人。呵呵,那是只不過是想忘掉乙個人。但是,2 年了。發現根本就是忘不掉。昨天偷偷的上了好久停用的qq,看見了她個人簡介的一些話。自己只...

頹廢的三天

47集,晚上熬到3點半,身體特別累,所以這幾天就沒有再寫東西。豆瓣描述 宋運輝 王凱飾 天資聰穎,卻出身不好,一直倍受歧視,但是他把握住了1978年恢復高考的機會,抓住機遇,勤學苦幹,當上了國企的技術人員,一步步晉公升,奠定了成功人生的基礎,但也在新時代的變革中逐漸迷失。與宋運輝不同的是他的姐夫雷東...