POJ3659树的最小支配集

版权声明:转就转吧~~记得声明噢~~ https://blog.csdn.net/Soul_97/article/details/83628192

http://poj.org/problem?id=3659

最小支配集:对于图G = (V, E) 来说,最小支配集指的是从 V 中取尽量少的点组成一个集合, 使得 V 中剩余的点都与取出来的点有边相连.也就是说,设 V' 是图的一个支配集,则对于图中的任意一个顶点 u ,要么属于集合 V', 要么与 V' 中的顶点相邻. 在 V' 中除去任何元素后 V' 不再是支配集, 则支配集 V' 是极小支配集.称G 的所有支配集中顶点个数最少的支配集为最小支配集,最小支配集中的顶点个数称为支配数.

最小支配集

贪心策略:首先选择一点为树根,再按照深度优先遍历得到遍历序列,按照所得序列的反向序列的顺序进行贪心,对于一个即不属于支配集也不与支配集中的点相连的点来说,如果他的父节点不属于支配集,将其父节点加入到支配集.

对于本题:对于一个点来说,如果它的孩子没有被覆盖,它和它的父亲也没有被覆盖,那么就覆盖它的父亲,结点数+1

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iterator>
#include <cctype>
#include <sstream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <deque>
#include <queue>
#include <list>
#include <functional>
using namespace std;
typedef long long ll;
const int N = 1e4 + 5;
const double INF = 99999999;
const int mod = 1e9 + 7;
vector<int> g[N];
int n, ans, vis[N], cover[N];
void dfs(int k,int fa)
{
    bool flag = false;
    vis[k] = 1;
    for(int i = 0;i < g[k].size();i ++){
        int t = g[k][i];
        if(!vis[t]){
            dfs(t,k);
            if(cover[t]){
                flag = true;
            }
        }
    }
    if(fa == 0){
        if(!flag && !cover[k]){
            cover[k] = 1;
            ans ++;
        }
    }else if(!flag && !cover[fa] && !cover[k]){
        cover[fa] = 1;
        ans ++;
    }
}
int main()
{
    cin >> n;
    for(int i = 1;i < n;i ++){
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    ans = 0;
    dfs(1,0);
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Soul_97/article/details/83628192