现在的位置: 首页 > 综合 > 正文

LA 2038 Strategic game

2013年10月24日 ⁄ 综合 ⁄ 共 1362字 ⁄ 字号 评论关闭

树形DP

题意: 给定一棵树,选择尽量少的节点,使得每个没有选中的节点至少和一个已选节点相邻。

解法: 关于树形DP,题目通常给的是无根树,那么随便选择一个节点当做根好了,这不影响解题。题目的限制是,如果一个节点没被选中,那么和它相邻的节点至少选一个,若一个节点已选,那么和它相邻的节点选或不选都可以。那么,在树中的体现是,对于一个非根节点,他的限制来自于它的父亲(对于根我们不设限制),若它的父亲没被选,则它必须被选,若选了它的父亲,则它选或不选都可以。

设状态dp[u][0]为以u为根的子树当u不选时的最小值,dp[u][1]为选了u的最小值。那么有如下转移:

dp[u][0] = sigma(dp[v][1]) v为u在树中的儿子。

dp[u][1] = sigma(max(dp[v][1],dp[v][0]))。

/* **********************************************
Author      : Nero
Created Time: 2013-8-26 12:19:21
Problem id  : LA 2038
Problem Name: Strategic game
 *********************************************** */

/*

树形DP,题目不难,但是唯一的巨大的坑是,书上描述n=0为结束标志,但是网页上的题目没有这一句,所以轻信者得RE。

*/

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define REP(i,a,b) for(int i=(a); i<(int)(b); i++)
#define clr(a,b) memset(a,b,sizeof(a))

const int MAXN = 1510;
struct Edge {
    int v,next;
}g[MAXN<<1];
int head[MAXN],tot;
int dp[MAXN][2];
int mark[MAXN];

void add_edge(int u, int v) {
    g[tot].v = v;
    g[tot].next = head[u];
    head[u] = tot ++;
}

int dfs(int u, int fa, int x) {
    if(!mark[u]) {
        dp[u][0] = 0;
        dp[u][1] = 1;
        for(int p = head[u]; p != -1; p=g[p].next) {
            int v = g[p].v;
            if(v == fa) continue;
            dp[u][0] += dfs(v,u,0);
            dp[u][1] += dfs(v,u,1);
        }
        mark[u] = 1;
    }
    if(x == 1) return min(dp[u][0],dp[u][1]);
    else return dp[u][1];
}

int main() {
    int n;
    while(~scanf("%d", &n)) {
        clr(head, -1);
        clr(mark,0);
        tot = 0;
        int m,a,u;
        REP(i,0,n) {
            scanf("%d", &u);
            scanf(":(%d)", &m);
            while(m--) {
                scanf("%d", &a);
                add_edge(u,a);
                add_edge(a,u);
            }
        }
        printf("%d\n", dfs(0,-1,1));
    }
    return 0;
}

抱歉!评论已关闭.