看起來很有趣。來提升一下亂搞技巧。
3 一般圖的獨立集問題
3.1 基於極大獨立集搜索的獨立集算法
顯然最大獨立集一定是極大獨立集,所以考慮把極大獨立集搜出來,也許能帶來優化。
3.1.2 極大獨立集與 Bron-Kerbosch 算法
其實是一個很簡單的算法。考慮任意一個點 \(u\) ,那么 \(u\cup N(u)\) 里面顯然至少會有一個點在極大獨立集內。
現在維護集合 \(R,P,X\) ,分別表示已經確定的當前集合、還可以加入的點的集合、欽定不能加入的點的集合。找到 \(u\in P\cup X\) 。使得 \(|u\cup N(u)|\) 最小,然后枚舉 \(v\in P\cap (u\cup N(u))\) :
- 遞歸搜索 \(R\cup v,P-(v\cup N(v)),X-(v\cup N(v))\) 。
- 把 \(v\) 從 \(P\) 中刪去,加入 \(X\) 。
顯然所有極大獨立集都會被搜到。
3.1.3 極大獨立集的個數
上面這個算法可以被證明遞歸調用次數是 \(O(3^{n/3})\) 的。
然后可以算算隨機圖的期望極大獨立集個數,有
3.2 基於動態規划的獨立集算法
DP 當然更高級一點,還可以求解獨立集計數等問題。
但這個 DP 其實近於爆搜:直接設 \(dp_S\) 表示 \(G[S]\) 上的最大獨立集,然后隨便拿出一個點 \(v\) ,就有
如果每次拿出編號最大的點,那么可以做到不重不漏,並且復雜度 \(O(2^{n/2})\) ,因為前 \(n/2\) 層每層只有 2 種遞歸的可能,后 \(2^{n/2}\) 層 \(S\) 只包含后面 \(n/2\) 個點。卡滿也非常簡單,放 \(n/2\) 個獨立的兩個點的連通塊即可。或者如果沒加剪枝的話 \(m=0\) 的圖就可以卡滿了。
然后是兩個簡單的剪枝:
- \(v\) 取 \(G[S]\) 中度數最大的點。顯然這樣還是不重不漏。
- \(S\) 不連通時拆開分別計數。
這樣就跑得飛快。
還有一個優化是在 \(G[S]\) 是一棵樹時改成樹形 DP ,但好像沒啥用。
一個小問題是這個算法的空間復雜度比較爆炸,可以只記憶化 \(S\) 較小的 \(dp\) 值。
求所有大小為 \(k\) 的獨立集的權值(所有點權值之積)之和的簡單代碼:
ll W[sz],out[sz];
map<ll,vector<ll>>dp;
vector<ll> work(ll S)
{
vector<ll>res; int c=__builtin_popcountll(S); res.resize(c+1);
if (!S) return res[0]=1,res;
if (dp.count(S)) return dp[S];
if (c>10)
{
ll cur=S&-S;
rep(i,1,c) rep(k,0,n-1) if (cur>>k&1) cur|=out[k],cur&=S;
if (cur!=S)
{
auto r1=work(cur),r2=work(S^cur);
rep(i,0,(int)r1.size()-1) rep(j,0,(int)r2.size()-1) (res[i+j]+=r1[i]*r2[j]%mod)%=mod;
return res;
}
}
int mx=-1,p=-1; rep(i,0,n-1) if ((S>>i&1)&&chkmax(mx,__builtin_popcountll(S&out[i]))) p=i;
auto r1=work(1ll<<p^S); rep(i,0,c-1) res[i]=r1[i];
auto r2=work(S&(~out[p])); rep(i,0,(int)r2.size()-1) (res[i+1]+=r2[i]*W[p])%=mod;
if (c<=n/2) dp[S]=res; return res;
}
3.2.4 測試與對比
4 特殊圖的獨立集問題
二分圖大家都會,分層圖也沒什么好說的。
4.4 "\(k\)-仙人圖" 上的動態規划
仙人掌的 dfs 樹滿足每條樹邊最多被非樹邊覆蓋一次,所以也可以隨便 DP 。更進一步,如果滿足每條邊最多屬於 \(k\) 個簡單環,其中 \(k\) 為常數,那么都可以在樹上狀壓 DP 解決。
4.1.2 無爪圖的最大獨立集
在無爪圖 (claw-free graph) 上也有多項式做法。無爪圖就是不存在 \(K_{1,3}\) 導出子圖的圖。
集訓隊論文把這一段寫得很簡略,於是我跑去看了參考資料。
我就是論文翻譯機
有一個類比:考慮一個任意圖的線圖,它都一定是一個無爪圖。線圖上的獨立集就會對應回原圖的一個匹配,而一般圖匹配算法是有多項式做法的。
然而並不是任意一個無爪圖都能對應回一個原圖,所以還要操作。
無爪圖有一個重要性質:兩個獨立集的對稱差的導出子圖滿足每個點的度數都小於等於 2 ,不難證明。也就是說對稱差的導出子圖的每個連通塊要么是環,要么是鏈。
設 \(I_1,I_2\) 為兩個獨立集,且 \(|I_1|<|I_2|\) ,那么 \(I_1\Delta I_2\) 一定有一條鏈,滿足首尾都不屬於 \(I_1\) 。翻轉這條鏈的狀態即可使得 \(|I_1|\) 增大。
所以從 \(I=\varnothing\) 開始,設黑點為在 \(I\) 中的點,白點為不在 \(I\) 中的點。每次的目標就是找到一條黑白交錯的鏈,滿足鏈上的點兩兩不同,任意兩個白點不相鄰,首尾都為白色,且首尾都只和一個黑點相鄰。鏈長度 \(\le 3\) 可以先特判掉。
無爪圖的一個性質:以下兩個圖不可能作為子圖(不一定是導出子圖)存在。
於是“任意兩個白點不相鄰”可以寫得更簡潔一點,只需要滿足首尾不相鄰且隔着一個黑點的白點不相鄰即可。畫畫圖即可證明。
現在可以枚舉起終點,刪除所有和它們相鄰的白點,刪除所有只和一個黑點相鄰的白點,然后嘗試找一條增廣路。現在的圖還滿足性質:兩個白點之間有邊,僅當它們與一個公共黑點相鄰(證明見上圖右邊)。把現在這個圖叫做一個 Reduced Basic Structure (RBS) 。
4. A Useful Theorem
然后證明一個(暫時看不懂有什么用的)定理。設 \(S\) 是一個非空集合, \(R\) 是一個 symmetric relation on S 。記 \(xRy\) 表示 x is related to y ,否則 \(xR'y\) 。設 T-property 對於三元組 \((x,y,z)\) 滿足,當且僅當 \(xRy,yRz,zRx\) 恰好有奇數個成立。可以發現如果 T-property 對於所有三元組成立,那么 \(R\) 是在 \(S\) 上的一個等價關系,並且把 \(S\) 划分為至多兩個等價類。
現在設 \(\{S_\alpha:\alpha\in A,\text {an index-set}\}\) 為一個對 \(S\) 的固定的划分,且划分出來至少三個非空子集。把划分出來的子集叫做 wings 。對於一個 symmetric relation \(R\) ,定義 \(x\bar{R}y\) 當且僅當 \(xRy\) 且 \(x,y\) 屬於不同的 wing 。也就是說 \(\bar R\) 只保留 \(R\) 關於不同 wing 的元素的信息。如果 \(R\) 對於兩兩不在同一個 wing 的三元組 \((x,y,z)\) 滿足 T-property ,那么就稱 \(R\) 滿足 PT-property ,且顯然 \(\bar R\) 也滿足。
可以證明,如果 \(L\) 滿足 PT-property ,那么存在唯一的一個 \(R\) ,使得 \(\bar R=\bar L\) ,且 \(R\) 對於所有 \((x,y,z)\) 都滿足 T-property 。
上面有點不說人話。就是對於一個完全 \(k\)-分圖 (\(k\ge 3\)) ,任取一種給邊紅綠染色的方案,使得任意一個三角形都有奇數個紅邊,那么就有唯一一種給點黑白染色(不考慮 swap(black,white)
)的方案,使得紅邊連接同色點,綠邊連接不同色點。
證明這個東西有什么用呢?注意到圖中
上面兩個不可能作為導出子圖出現,而下面兩個可能出現。
5. Classification Of Black Vertices
現在考慮一個 RBS ,我們來把黑點分類。
任取一個黑點,考慮和它相鄰的白點,把這些白點按照相鄰的另一個黑點分成幾個 wings ,每個 wing 中的另一個黑點叫做 the tip of the wing 。如果這些白點中有一個是只和它相鄰的(即增廣路的起點或終點),那么把這個黑點叫做“一類規則點”;否則如果它有至少 3 個 wings ,那么叫做“二類規則點”;否則如果有恰好兩個 wings ,那么叫做“不規則點”;否則叫做垃圾“無用點“。
顯然無用點和與它相鄰的白點可以全部刪掉。
(省略了白點之間的連邊)
(注意這個結構與 Figure 3,4 之間的關系)
(整個圖就是由若干個這樣的結構拼成的,已經看到解題的希望了)
注意到一個增廣路就是經過了若干個 wings ,每個 wing 踩一個白點,所以同一個 wing 的白點之間的邊已經不重要了。
現在對於每個“規則點”,用如下方法把相鄰的白點分成兩個子集。
對於一類規則點,把起點/終點單獨放一個類型,其他點全部放到另一個類型;對於二類規則點,按照 wing 把點集拆開,然后設 \(\bar L\) 表示兩個不同 wing 的點之間是否有邊,然后就可以用上面那個定理唯一地把點集拆成兩個等價類。
這個定理的作用已經浮現出來了:同一個 wing 內部的邊對最終結果沒有影響,所以不需要考慮,任意分配。分成兩個等價類之后,就只能從一邊走到另一邊了。
7. Construction Of The Edmonds'-Graph
已經不是很想繼續看了。
大概是把黑點換回黑邊,分成的兩個白點等價類分別變成連向黑邊的兩個端點的一堆白邊,然后就得到原圖了。這個原圖的線圖雖然不是當前的圖,但應該性質是類似的。
(顯然這句話很不嚴謹)
所以就可以用類似帶花樹的算法求出增廣路。
(學完之后感覺沒什么用啊,我又寫不出來 /kk )