洛谷

洛谷题单指南-树与图上的动态规划-P2016 战略游戏

原题链接:https://www.luogu.com.cn/problem/P2016

题意解读:在树中选择最少的节点,使得可以覆盖整个树,一个节点可以覆盖所有分支以及子节点。

解题思路:

1、状态表示

f[i][0]表示以i为根的子树且不选i的最少士兵数量,f[i][1]表示以i为根的子树且选i的最少士兵数量

2、状态转移

对于u的所有子节点v,

如果不选u,则子节点只能选, 因此有f[u][0] += f[v][1]

如果选u,则子节点可以选或不选,因此有f[u][1] +=min(f[v][0], f[v][1])

3、初始值

f[u][0] =0

f[u][1] =1

4、答案

min(f[0][0], f[0][1])
100分代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 2000;

vector<int> g[N];
int f[N][2]; // f[i][0]表示以i为根的子树且不选i的最少士兵数量,f[i][1]表示以i为根的子树且选i的最少士兵数量
int n;

void dfs(int u, int fa)
{
    f[u][0] = 0; //不选u时
    f[u][1] = 1; //选u时
    for(int v : g[u])
    {
        if(v == fa) continue; 
        dfs(v, u);
        f[u][0] += f[v][1]; //如果不选u,则子节点只能选
        f[u][1] += min(f[v][0], f[v][1]); //如果选u,则子节点可以选或不选
    }
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) 
    {
        int u, k;
        cin >> u >> k;
        while(k--)
        {
            int v;
            cin >> v;
            g[u].push_back(v);
            g[v].push_back(u); //树要双向建边,任意点都能当做根节点
        }
    }
    dfs(0, -1); 
    cout << min(f[0][0], f[0][1]);
    return 0;
}