1. 程式人生 > >洛谷2016 戰略遊戲 (0/1狀態的普通樹形Dp)

洛谷2016 戰略遊戲 (0/1狀態的普通樹形Dp)

題意:

給出一個樹,覆蓋樹上某一個點的花費為w[i],求樹上每一條邊至少有一個點覆蓋的最小花費。

細節:

1.一條邊的兩端可以均被覆蓋,但是不能存在一條邊的兩端都不被覆蓋。
2.可能存在

分析:

對於一對兒子和父親節點來說,要麼兒子覆蓋父親不覆蓋,父親覆蓋兒子不覆蓋,或者是兩者均被覆蓋,所以不難發現對於父親節點來說,若其被覆蓋,則它的所有子孫可以被覆蓋也可以不被覆蓋,若其不被覆蓋,則它的子孫必須可以被全部覆蓋。

所以狀態變得顯然:dp[u][0/1] 表示節點 u 是否被覆蓋的最小花費
再根據上方的分析條件轉移如下:
dp[u][1] = ∑ min( dp[v][0] , dp[v][1] )


dp[u][0] = ∑ dp[v][1]

程式碼

#include<bits/stdc++.h>
#define MAXN 1505
using namespace std;

int f[MAXN][2], n;
vector<int> Right[MAXN];

void dfs(int u, int fa){
    f[u][0]=0, f[u][1]=1;
    for (int i=0; i<Right[u].size(); i++) {
        int v=Right[u][i];
        if (v==fa) continue;
        dfs(v, u);
        f[u][0]+=f[v][1];
        f[u][1]+=min(f[v][0], f[v][1]);
    }
}

int main(){
    scanf("%d", &n);
    for (int i=1, x, num; i<=n; i++) {
        scanf("%d%d", &x, &num);
        for (int j=1, y; j<=num; j++) {
            scanf("%d", &y);
            Right[x].push_back(y);
            Right[y].push_back(x);
        }
    }
    dfs(1, -1);
    printf("%d\n", min(f[root][0], f[root][1]));
    return 0;
}

Ps:

此題與 DAY2T344 分演算法十分雷同,但是我死在了考場的一線上……