AcWing 323. 战略游戏(树形dp scanf格式化输入)

AcWing 323. 战略游戏(树形dp scanf格式化输入)_第1张图片
AcWing 323. 战略游戏(树形dp scanf格式化输入)_第2张图片
AcWing 323. 战略游戏(树形dp scanf格式化输入)_第3张图片
AcWing 323. 战略游戏(树形dp scanf格式化输入)_第4张图片
本题是 AcWing 285. 没有上司的舞会 的对偶题

题意:

每条边上至少选择一个节点,可以选择的最小权值。

思路:

树形dp,与没有上司的舞会具有对称性

没有上司的舞会:每条边上最多选择一个点,求最大点权值之和

战略游戏:每条边上最少选择一条点求最小点权值之和(每个点权值都为 1)

状态表示

f[u][0]:所有以u为根的子树中选择,并且不选u这个点的方案

f[u][1]:所有以u为根的子树中选择,并且u这个点的方案

属性Min

状态计算

当前u结点不选,子结点一定选

f [ u ] [ 0 ] = ∑ ( f [ s i , 1 ] ) f[u][0]=∑(f[si,1]) f[u][0]=(f[si,1])

当前u结点选,子结点一定可选可不选

f [ u ] [ 1 ] = ∑ m i n ( f [ s i , 0 ] , f [ s i , 1 ] ) f[u][1]=∑min(f[si,0],f[si,1]) f[u][1]=min(f[si,0],f[si,1])

时间复杂度 :

O ( n ) O(n) O(n)

代码:

#include

using namespace std;
const int N = 1510;
int n;
int h[N], e[N], ne[N], idx;
int dp[N][2];
bool st[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void dfs(int u)
{
    dp[u][0] = 0, dp[u][1] = 1;
    for(int i=h[u]; ~i; i=ne[i])
    {
        int j=e[i];
        dfs(j);
        dp[u][0] += dp[j][1];
        dp[u][1] += min(dp[j][0], dp[j][1]);
    }
}

int main()
{
    while(~scanf("%d", &n))
    {
        memset(h, -1, sizeof h);
        memset(st, false, sizeof st);
        idx = 0;
        for(int i=0; i

你可能感兴趣的:(树形dp,深搜,动态规划,c++,算法,动态规划)