樹的最小支配集,最小點覆蓋與最大獨立集
阿新 • • 發佈:2019-02-01
首先看一下三者的定義:
定義1 對於圖G=(V,E)來說, 最小支配集 指的是從V中取儘量少的點組成一個集合,使得對於V中剩餘的點都與取出來的點有邊相連。也就是說,設V‘是圖G的一個支配集,則對於圖中的任意一個頂點u,要麼屬於集合V’,要麼與V‘中的頂點相鄰。在V’中出去任何元素後V‘不再是支配集,則支配集是極小支配集。稱G的所有支配集中頂點個數最少的支配集為最小支配集,最小支配集中頂點的個數稱為支配數。
定義2 對於圖G=(V,E)來說, 最小點覆蓋 指的是從V中取儘量少的點組成一個集合,使得E中所有的邊都與取出來的點相連。也就是說,設V‘是圖G的一個頂點覆蓋,則對於圖中的任意一條邊(u,v),要麼u屬於集合V’,要麼v屬於集合V‘。在V‘中除去任何元素後V’不在是頂點覆蓋,則V‘是極小頂點覆蓋。稱G的所有頂點覆蓋中頂點個數最少的覆蓋為最小點覆蓋。
定義3 對於圖G=(V,E)來說, 最大獨立集 指的是從V中取儘量多的點組成一個集合,使得這些點之間沒有邊相連。也就是說,設V’是圖G的一個獨立集,則對於圖中任意一條邊(u,v),u和v不能同時屬於集合V',甚至可以u和v都不屬於集合V‘。在V’中新增任何不屬於V‘元素後V’不再是獨立集,則V‘是極大獨立集。稱G的所有頂點獨立集中頂點個數最多的獨立集為最大獨立集。
對於任意圖G來說,這三個問題不存在多項式時間的解法。 不過對於樹來說,卻很容易。目前有兩種解法,一種基於貪心思想,另一種基於樹形動態規劃思想。
求解(貪心演算法):對整棵樹進行dfs,求出dfs序,然後進行貪心。以求支配集為例,對於兒子和父親,肯定選父親能影響到的更多,那麼只要把最小面一層確定後就可以從後往前進行判斷了。
1 int p[maxn]; 2 bool select[maxn]; 3 int newpos[maxn]; 4 int now; 5 int n,m; 6 void DFS(int x) 7 { 8 newpos[now++]=x; 9 int k; 10 for(k=head[x];k!=-1;k=edge[k].next) 11 { 12 if(!select[edge[k].to]) 13 { 14 select[edge[k].to]=true; 15 p[edge[k].to]=x;View Code16 DFS(edge[k].to); 17 } 18 } 19 }
對於最小支配集,貪心函式如下:
1 int greedy() 2 { 3 bool s[maxn]; 4 bool set[maxn]={0}; 5 int ans=0; 6 int i; 7 for(i=n-1;i>=0;i--) 8 { 9 int t=newpos[i]; 10 if(!s[t]) 11 { 12 if(!set[p[t]]) 13 { 14 set[p[t]]=true; 15 ans++; 16 } 17 s[t]=true; 18 s[p[t]]=true; 19 s[p[p[t]]]=true; 20 } 21 } 22 return ans; 23 }View Code
對於最小點覆蓋,貪心函式如下:
1 int greedy() 2 { 3 bool s[maxn]={0}; 4 bool set[maxn]={0}; 5 int ans=0; 6 int i; 7 for(i=n-1;i>=1;i--) 8 { 9 int t=newpos[i]; 10 if(!s[t]&&s[p[t]]) 11 { 12 set[p[t]]=true; 13 ans++; 14 s[t]=true; 15 s[p[t]]=true; 16 } 17 } 18 return ans; 19 }View Code
對於最大獨立集,貪心函式如下:
1 int greedy() 2 { 3 bool s[maxn]={0}; 4 bool set[maxn]={0}; 5 int ans=0; 6 int i; 7 for(i=n-1;i>=0;i--) 8 { 9 int t=newpos[i]; 10 if(!s[t]) 11 { 12 set[t]=true; 13 ans++; 14 s[t]=true; 15 s[p[t]]=true; 16 } 17 } 18 return ans; 19 }