UVALive 7003 A Balance Game on Trees 树形dp

来源:互联网 发布:网络存储的用处 编辑:程序博客网 时间:2024/05/30 02:53

题意:

有一颗<=100的树,树上的节点一开始全部都是白色。

现在要求,每个白色节点必须刚好和k个黑点相邻,不能则将其染黑,问你最终最多可以有多少个白色节点保留。


思路:

树形dp

特判掉k = 0的情况;

dp[i][j][z]:以i为根节点的子树,节点i的颜色为j,和它相连有z个黑色节点所得到的最多的白色节点个数。


由于z只有k-1和k两种状态是有用的。因此我们只需要处理出三种状态。

dp[i][0][0]:i节点白色,子树有k-1个黑色节点与i相邻

dp[i][0][1]:i节点白色,子树有k歌黑色节点与i相邻

dp[i][1][0]:i节点黑色,有多少个黑色节点都无所谓


当前节点i,对于i的直接儿子节点,我们只要再进行一次dp将它们合并即可。

dp2[t][p]:前t个儿子节点,有p个黑色节点与i相邻,所得到的最大白色节点个数。


具体转移看代码(写得比较挫= =)

code:

#include <bits/stdc++.h>using namespace std;const int N = 105;typedef long long LL;int n, k;char ch[10000];int dp[N][2][2];int dp2[2][N];int head[N], ec = 0;struct PP {    int v, next;}edge[N<<1];void addEdge(int u, int v) {    edge[ec] = (PP){v, head[u]};    head[u] = ec++;}void dfs(int u, int par) {    bool flag = false;    vector <int> a, b, c;    for(int i = head[u];i != -1; i = edge[i].next) {        int v = edge[i].v;        if(v == par) continue;        dfs(v, u);        flag = true;        a.push_back(dp[v][0][1]);       //k        b.push_back(dp[v][1][0]);        c.push_back(dp[v][0][0]);       //k-1    }    //leaf node    if(!flag) {        if(k == 1) {            dp[u][0][0] = 1;            dp[u][0][1] = -1;            dp[u][1][0] = 0;        }        else {            dp[u][0][0] = dp[u][0][1] = -1;            dp[u][1][0] = 0;        }        return ;    }    //deal    memset(dp2, -1, sizeof(dp2));    dp2[0][0] = 0;    int cur = 0;    int n = a.size();    for(int i = 0;i < n; i++) {        for(int j = 0;j <= n; j++) {            if(dp2[cur][j] == -1) continue;            if(a[i] != -1) {                dp2[cur^1][j] = max(dp2[cur^1][j], dp2[cur][j]+a[i]);            }            if(b[i] != -1) {                dp2[cur^1][j+1] = max(dp2[cur^1][j+1], dp2[cur][j]+b[i]);            }            dp2[cur][j] = -1;        }        //memset(dp2[cur], -1, sizeof(dp2[cur]));        cur ^= 1;    }    //dp[u][0][0], dp[u][0][1];    if(dp2[cur][k-1] != -1) dp[u][0][0] = dp2[cur][k-1]+1;    if(dp2[cur][k] != -1) dp[u][0][1] = dp2[cur][k]+1;    //dp[u][1][0]    dp[u][1][0] = 0;    for(int i = 0;i < n; i++) {        dp[u][1][0] += max(b[i], c[i]);    }}void solve() {    if(k == 0) {        printf("%d\n", n);        return ;    }    memset(dp, -1, sizeof(dp));    dfs(1, -1);    printf("%d\n", max(dp[1][0][1], dp[1][1][0]));}    int main() {    int T;    scanf("%d", &T);    while(T--) {        memset(head, -1, sizeof(head)), ec = 0;        scanf("%d%d", &n, &k);        int tmp;        getchar();        for(int i = 1;i <= n; i++) {            gets(ch);            stringstream str(ch);            while(str>>ch) {                sscanf(ch, "%d", &tmp);                if(tmp == 0) break;                addEdge(i, tmp);                addEdge(tmp, i);            }        }        solve();    }    return 0;}




0 0
原创粉丝点击