帶花樹總結

2022-04-28 22:09:30 字數 1500 閱讀 3904

匈牙利演算法(二分圖最大匹配)

考慮一下二分圖和一般圖的最大區別(或者說唯一的區別在**)。

二分圖沒有奇環(也就是長度為奇數的環),而一般圖是可以有的。

所以匈牙利演算法中的尋找增廣路然後路徑取反的方法在一般圖上就不適用了。

主要還是要解決奇環的問題。

我們發現乙個奇環裡至少有乙個點不能匹配,那就乾脆把乙個奇環縮成乙個點(開花)?

在處理到奇環的時候把它縮成乙個點,路徑取反的時候再暴力展開乙個個取反。

我們給所有點黑白染色。假設開始增廣的點是黑點。

把所有黑點壓進佇列中順次處理。對於乙個黑點\(u\),找與他相鄰的點\(v\),會出現一下幾種情況:

1、\(u,v\)已經被縮成乙個點了(這兩個點在一朵花裡),不管他。

2、\(v\)是白點,說明已經被匹配了,也不管。

3、\(v\)還沒有被染色。那就先把這個點染成白的,然後嘗試去與他匹配。如果\(v\)還沒有匹配就匹配上,增廣成功,然後一路跳回取反。如果\(v\)已經被匹配了,那麼匹配他的點就是個黑點,染色,然後壓進佇列。

4、\(v\)也是黑點。這時候染色發生了衝突,說明遇見了奇環。這時候就需要找到兩個點的\(lca\),然後把這整個環縮成乙個點。美其名曰,開花。

開花的時候大致要做這麼幾件事:(摘自無向圖匹配的帶花樹演算法)

1。找\(x\)和\(y\)的\(lca\)(的根)\(p\)。找\(lca\)可以用各種方法。。。直接樸素也行。

2。在\(pre\)陣列中把\(x\)和\(y\)接起來(表示它們形成環了!)

3。從\(x\)、\(y\)分別走到\(p\),修改並查集使得它們都變成一家人,同時沿路把\(pre\)陣列接起來。

uoj79 一般圖最大匹配

#include#include#include#includeusing namespace std;

int gi()

const int n = 505;

int n,m,to[n*n<<1],nxt[n*n<<1],head[n],cnt;

int match[n],pre[n],vis[n],fa[n],tim[n],idx,ans;

queueq;

int link(int u,int v)

int find(int x)

int lca(int x,int y)

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

}int aug(int s)

vis[match[v]]=1,q.push(match[v]);

}else

}} return 0;

}int main()

for (int i=1;i<=n;++i) if (!match[i]) ans+=aug(i);

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

for (int i=1;i<=n;++i) printf("%d ",match[i]);

puts("");return 0;

}

模板 帶花樹

學習部落格 那些年我用帶花樹做過的題目 帶花樹板子 include using namespace std const int n 1200 10 int n,m,k inline intread namespace flowertree e 300 600 6 10 int head n tot ...

筆記 帶花樹

帶花樹用來解決一般圖的最大匹配問題。考慮不能直接增廣的原因是存在奇環。帶花樹的思路是把奇環給縮成一朵花。然後仍然通過增廣路演算法實現擴大匹配數目。其中能縮成一朵花的原因是。一堆點縮成花之後能夠成為增廣路中的某乙個點,那麼原圖也可以。這樣就簡化了模型從而可以直接用 bfs 增廣。1.uoj79 模板題...

帶花樹草解

這個東西其實看看就好,n 3 次的做法雖說也是多項式複雜度但總給人很暴力的感覺.我們都知道二分圖最大匹配可以匈牙利 網路流,因為二分圖只有一邊連向另一邊,換句話說就是不存在奇環 可以簡單證明 這是增廣路演算法可以解決的 對於有向無環圖,網路流演算法也可以跑得非常優秀,但是對於一般圖來說,這兩個演算法...