版权声明:转就转吧~~记得声明噢~~ 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;
}