rainyroad

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

题意:给定一棵树,从中选出一些节点,使得不成父子关系的节点对数最多。问这个最大值是多少。

思路:首先既然是给定一颗树,先要选择合适的数据结构,来保存这颗树。由于这颗树只关心根节点在哪里,所以只需要用一个fa数组来保存每个点的根节点,此外设初始化为0,所以根节点的fa[root]为0,所以从任意一个结点的父节点往上遍历,直到遍历到某某个结点的父节点为0,则这个结点就是父节点

这道题个人感觉关键是从根节点开始往下dp,所以根节点要确定..

这道题的状态转移方程为,dp[i][1],选用第i个节点时,所能得到的最大对数,dp[i][0]不选用第i个节点时所能得到的最大对数,dp[i][0]=求和max(dp[j][0],dp[j][1]);dp[i][1]=求和dp[j][0].所以每一个父节点都依赖于它的子节点。所以递归求每一个子节点的dp[j]的值,最后在累加到dp[i]上,而边界条件是,递归到叶子节点时,dp[i][0]=0,dp[i][1]=1;加上代码

int n;  // 结点个数
int dp[maxn][2];  // dp[i][0] 表示不选择结点 i,dp[i][1] 表示选择结点 i
int father[maxn];  // father 记录了结点的父结点编号

void tree_dp(int node) {
    dp[node][0] = 0;
    dp[node][1] = 1for(int i = 1; i <= n; i++) {
        if(father[i] == node) {  // i 为 node 的子结点
            tree_dp(i);  // 递归计算子结点
            // 关键
            dp[node][1] += dp[i][0];  // 选择父结点,则必须不选择子结点
            dp[node][0] += max(dp[i][1], dp[i][0]);  // 不选择父结点,则可以选择或不选择子结点
        }
    }
}

int main() {
    int f, c, root;
    scanf("%d", &n);
    memset(father, 0, sizeof(father));
    memset(visited, 0, sizeof(visited));
    root = 0;  // 记录树的根结点
    while (scanf("%d %d", &c, &f), c || f) {  // 读入父子关系,前一个结点是后一个结点的孩子
        father[c] = f;
        root = f;
    }
    while(father[root]) {  // 查找根结点
        root = father[root];
    }
    tree_dp(root);  // 从根结点出发进行动态规划
    printf("%d\n", max(dp[root][0], dp[root][1]));  // 求出最终答案,根可以选或不选
    return 0;
}

 

posted on 2019-02-18 20:35  rainyroad  阅读(202)  评论(0编辑  收藏  举报