1. 程式人生 > >最小支配集講解

最小支配集講解

 

定義

最小支配集:對於圖G = (V, E) 來說,最小支配集指的是從 V 中取儘量少的點組成一個集合,

使得 V 中剩餘的點都與取出來的點有邊相連.也就是說,設 V' 是圖的一個支配集,則對於圖

中的任意一個頂點 u ,要麼屬於集合 V', 要麼與 V' 中的頂點相鄰. 在 V' 中除去任何元素後

V' 不再是支配集, 則支配集 V' 是極小支配集.稱G 的所有支配集中頂點個數最少的支配集

為最小支配集,最小支配集中的頂點個數稱為支配數.

求解

貪心策略:首先選擇一點為樹根,再按照深度優先遍歷得到遍歷序列,按照所得序列的反向序列的順序進行貪心,對於一個即不屬於支配集也不與支配集中的點相連的點來說,如果他的父節點不屬於支配集,將其父節點加入到支配集.

虛擬碼:

  第一步:以根節點深度優先遍歷整棵樹,求出每個點在深度優先遍歷序列中的編號和每個點的父節點編號.

  第二步:按照深度優先遍歷的反向順序檢查每個點,如果當前點不屬於支配集也不與支配集的點相連,且它的父節點不屬於支配集,將其父節點加入到支配集,支配集中點的個數加 1, 標記當前節點, 當前節點的父節點, 當前節點的父節點的父節點,因為這些節點要麼屬於支配集(當前點的父節點),要麼與支配集中的點相連(當前節點 和 當前節點的父節點的父節點).

具體實現:

  採用鏈式前向星儲存整棵樹.整形陣列newpos[i] 表示深度優先遍歷序列的第 i 個點是哪個點, now 表示當前深度優先遍歷序列已經有多少個點了. bool形陣列visit[]用於深度優先遍歷的判重,整形pre[i]表示點 i 的父節點編號,  bool型陣列s[i]如果為 true, 表示第 i 個點被覆蓋, bool型陣列set[i]如果為 true,表示點 i 屬於要求的點的集合.

程式碼

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1000;
int pre[maxn];//儲存父節點
bool visit[maxn];//DFS標記陣列
int newpos[maxn];//遍歷序列
int now;
int n, m;

int head[maxn];//鏈式前向星
struct Node {int to; int next;};
Node edge[maxn];

void DFS(int x) {
    newpos[now ++] = x;//
記錄遍歷序列 for(int k = head[x]; k != -1; k = edge[k].next) { if(!visit[ edge[k].to ]) { visit[ edge[k].to ] = true; pre[edge[k].to] = x;//記錄父節點 DFS(edge[k].to); } } } int MDS() { bool s[maxn] = {0}; bool set[maxn] = {0}; int ans = 0; for(int i = n - 1; i >= 0; i--) {//逆序進行貪心 int t = newpos[i]; if(!s[t]) { //如果當前點沒被覆蓋 if(! set[ pre[t] ]) {//當前點的父節點不屬於支配集 set[ pre[t] ] = true;//當前點的父節點加入支配集 ans ++; //支配集節點個數加 1 } s[t] = true; //標記當前點已被覆蓋 s[ pre[t] ] = true;// 標記當前點的父節點被覆蓋 s[ pre[ pre[t] ] ] = true;//標記當前點的父節點的父節點被覆蓋 } } return ans; } int main() { /* read Graph message*/ //建圖 memset(visit, false, sizeof(visit));//初始化 now = 0; visit[1] = true; pre[1] = 1; DFS(1);//從根節點開始尋摘遍歷序列 MDS(); return 0; }
View Code

 

 

轉載:http://www.cnblogs.com/Ash-ly/p/5775934.html