最小支配集,最大独立集,最小点覆盖参考博客https://www.cnblogs.com/Ash-ly/p/5775934.html
最小支配集:选出一些点让这些点与剩下的点都有边且选出的点最少
首先我们先深度优先搜素一下将所有点标记一下顺序然后我们将点的父亲标记记录一下
最后反向贪心选择点,如果这个点没有被标记,我们就将他父亲加进点集里面标记这个点 ,父节点,父节点的父节点(至于为什么反向贪心,因为从最后一个点开始基本都有父亲从前面开始有些店没有父亲);
练习题: https://ac.nowcoder.com/acm/contest/1069/A
代码实现如下
#include <bits/stdc++.h>
typedef long long ll;
typedef long long ld;
using namespace std;
const ll maxn = 1e5 + 7;
ll pre[maxn],dfn[maxn];
bool flag[maxn],flag1[maxn];
vector<ll>mp[maxn];
ll cnt;
void dfs(ll x)
{
dfn[++cnt] = x;
for(int i = 0; i < mp[x].size(); i ++)
{
ll to = mp[x][i];
if(!flag[to])
{
pre[to] = x;
flag[to] = 1;
dfs(to);
}
}
}
vector<ll> b;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
ll n;
cin >> n;
for(int i = 1; i <= n - 1; i ++)
{
ll x,y;
cin >> x >> y;
mp[x].push_back(y);
mp[y].push_back(x);
}
flag[1] = 1;
dfs(1);
ll ans = 0;
memset(flag,0,sizeof(flag));
for(int i = cnt; i >= 1; i --)
{
if(!flag[dfn[i]])
{
if(!flag1[pre[dfn[i]]])
{
flag1[pre[dfn[i]]] = 1;
ans ++;
}
flag[dfn[i]] = 1;
flag[pre[dfn[i]]] = 1;
flag[pre[pre[dfn[i]]]] = 1;
}
}
cout << ans << endl;
return 0;
}