zoukankan      html  css  js  c++  java
  • # 0x54 动态规划-树形DP

    A.没有上司的舞会 基础树形DP

    emmm,蒟蒻发现自己的DP太辣鸡了。。。所以来练练DP,这题的话实际上应该算是树DP的入门题吧,转移还是挺好想的。

    每次在每个节点都会有个选择,就是选还是不选,如果选的话,那么它的儿子节点就不能选,如果不选的话它的儿子节点就可以选,也就是说我们需要另开一维状态来记录每个节点是否选自己的情况,那么就很容易得出如下方程:

    dp[x][0]+=max(0,max(dp[v][1],dp[v][0]));//如果不选当前节点,那么儿子节点可以任意选
    dp[x][1]+=max(0,dp[v][0]);//如果选择当前节点,那么只能选择儿子节点不存在的情况
    

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    vector<int>son[10010];
    int f[10010][2], v[10010], happy[10010], n;
    void dfs(int x) {
    	f[x][0] = 0, f[x][1] = happy[x];
    	for (int i = 0; i < son[x].size(); ++i) {
    		int y = son[x][i];
    		dfs(y);
    		f[x][0] += max(f[y][0], f[y][1]);
    		f[x][1] += f[y][0];
    	}
    }
    int main() {
    	//freopen("in.txt", "r", stdin);
    	cin >> n;
    	for (int i = 1; i <= n; ++i)cin >> happy[i];//快乐指数
    	for (int i = 1; i < n; ++i) {
    		int x, y; cin >> x >> y;
    		v[x] = 1; // x has a father
    		son[y].push_back(x);
    	}
    	int root;
    	for(int i = 1; i<= n;++i)
    		if (!v[i]) {
    			root = i; break;
    		}
    	dfs(root);
    	cout << max(f[root][0], f[root][1]) << endl;
    }
    

    算法竞赛进阶指南原文:

    正如深度优先和广度优先都可以对树或图进行遍历一样,除了自顶向下的递归外。我们也可以使用自底向上的Topo排序来执行树形DP。但通常前者就足够了。

    B.选课 背包类树形DP

    思路:

    每堂课和学它必修的课连一条边。为了方便,每个入度为0的课(即可以直接选的课)与一个虚拟的n+1节点连一条边,然后在树上跑01背包即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    vector<int> son[310];
    int f[310][310], s[310], n, m;
    
    void dp(int x) {
    	f[x][0] = 0;
    	for (int i = 0; i < son[x].size(); i++) { // 循环子节点(物品)
    		int y = son[x][i];
    		dp(y);
    		for (int t = m; t >= 0; t--) // 倒序循环当前选课总门数(当前背包体积)
    			for (int j = 0; j <= t; j++) // 循环更深子树上的选课门数(组内物品)
                    f[x][t] = max(f[x][t], f[x][t-j] + f[y][j]);
    			/* 或者
    			for (int j = t; j >= 0; j--)
    				if (t + j <= m)
    					f[x][t+j] = max(f[x][t+j], f[x][t] + f[y][j]);
    			这两种写法j分别用了正序和倒序循环
    			是为了正确处理组内体积为0的物品(本题正序倒序都可以AC是因为体积为0的物品价值恰好也为0)
    			请读者结合0/1背包问题中DP的“阶段”理论思考 */
    	}
    	if (x != 0) // x不为0时,选修x本身需要占用1门课,并获得相应学分
    		for(int t = m; t > 0; t--)
    			f[x][t] = f[x][t-1] + s[x];
    }
    
    int main()
    {
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++)
    	{
    		int x;
    		cin >> x >> s[i];
    		son[x].push_back(i);
    		
    	}
    	memset(f, 0xcf, sizeof(f)); // -INF
    	dp(0);
    	cout << f[0][m] << endl;
    }
    

    C.Accumulation Degree

  • 相关阅读:
    运行了unittest没有结果返回
    python学习笔记11.2-unittest的使用与报告生成
    python学习笔记11.1-类的继承与动态属性的设置
    docker概念
    python学习笔记10-方法
    python学习笔记9-类和对象
    python学习笔记8-异常处理
    python学习笔记2-字典和列表
    3.JavaScript-语法、关键保留字及变量
    如何实现导航菜单栏中的二级下拉菜单?
  • 原文地址:https://www.cnblogs.com/RioTian/p/13518385.html
Copyright © 2011-2022 走看看