题目大意

图片说明
对于任意一条边,其都只有两种被覆盖的可能:
1.被上面的节点(父节点)覆盖
2.被下面的节点(子节点)覆盖
故容易推出状态表示和方程
dp[i][j]:以i为根的子树的所有边被覆盖且i的状态为j的所有方案的数量最小值
(j = 0表示i不放士兵,j = 0为i放士兵)
转移方程
dp[i][0] = ∑(dp[son][1])
dp[i][1] = ∑(min(dp[son][1],dp[son][0]) + 1;
边界设置:对于叶子节点 dp[i][0] = 0, dp[i][1] = 1; 从定义出发
AC代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio> 
using namespace std;
#define IO std::ios::sync_with_stdio(false); cin.tie(0)
#define ll long long
#define ull unsigned long long
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define per(i, l, r) for (int i = l; i >= r; --i)
#define mset(s, _) memset(s, _, sizeof(s))
#define mcpy(s, _) memcpy(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define vi vector<int>
#define vpii vector<pii> 
#define mp(a, b) make_pair(a, b)
#define pll pair <ll, ll>
#define fir first
#define sec second
#define inf 0x3f3f3f3f
inline int lowbit(int x) {return x & -x;} 
template< typename T > inline void get_min(T &x, T y) {if(y < x) x = y;}
template< typename T > inline void get_max(T &x, T y) {if(x < y) x = y;}
inline int read() {
  int x = 0, f = 0; char ch = getchar();
  while (!isdigit(ch)) f |= ch == '-', ch = getchar();
  while (isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
  return f ? -x : x;
}
template<typename t> inline void print(T x) {
  if (x < 0) putchar('-'), x = -x;
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}
template<typename t> inline void print(T x, char let) {
  print(x), putchar(let);
}

const int N = 4e3 + 10, mod = 1e9 + 7;
int n, m;
int h[N], nex[N], v[N], idx;
void add(int a, int b) {
    v[idx] = b; nex[idx] = h[a]; h[a] = idx ++ ;
}

int f[N][5], st[N];
void init() {
    mset(h, -1); mset(f, 0); mset(st, 0); idx = 0;
}

void dp(int u) {
    bool fg = 0;
    for(int i = h[u]; ~i; i = nex[i]) {
        int j = v[i];
        fg = 1;
        dp(j);
        f[u][0] += f[j][1];
        f[u][1] += min(f[j][0], f[j][1]);
    }
    f[u][1] += 1;
    if(!fg) {
        f[u][0] = 0; f[u][1] = 1;
    }
}

int main() {
    while(cin >> n) {
        init();
        rep(i, 1, n) {
            int a, num, b; char t;
            cin >> a >> t >> t >> num >> t;
            rep(j, 1, num) {
                cin >> b; add(a, b); st[b] = 1;
            }
        }
        int root = 0;
        while(st[root]) root ++ ;
        dp(root);
        cout << min(f[root][1], f[root][0]) << endl;
    }

    return 0;
}

Cell Phone Network (https://ac.nowcoder.com/acm/problem/24953)

与 Strategic game的对比

树的最小支配集问题 与 树的最小点覆盖的对比

附上雨巨的画图解释
图片说明
研究对象不同导致状态转移的不同,前者研究的是覆盖住所有的点,树的任意一个点都可能被自身,儿子,父亲三者之一所覆盖,故状态转移有三种可能,后者研究的是覆盖所有的边,任意的边只可能连接两个节点,故状态转移只能来自二者之一</ll,></int,>