热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

寒假:Day4

Day4今天继续复习搞基础课,加油!树形DP每一个节点都分为选和不选两种状态,选为f[i,1],不选为f[i,0]&#
Day4

今天继续复习搞基础课,加油!

树形DP

每一个节点都分为选和不选两种状态,选为f[i, 1],不选为f[i, 0],每一个节点想要最大,他的每一个子树权值都必须最大,递归即可

不选择根节点的最大值:
f[i,0]=max(f[s1,0],f[s1,1])+max(f[s2,0],f[s2,1])+...+max(f[sk,0],f[sk,1])f[i, 0] = max(f[s1, 0], f[s1, 1]) + max(f[s2, 0], f[s2, 1]) +...+ max(f[sk, 0], f[sk, 1]) f[i,0]=max(f[s1,0],f[s1,1])+max(f[s2,0],f[s2,1])+...+max(f[sk,0],f[sk,1])
选择根节点的最大值:
f[i,1]=f[s1,0]+f[s2,0]+f[s3,0]+.....+f[sk,0]f[i, 1] = f[s1, 0] + f[s2, 0] + f[s3, 0] + ..... + f[sk, 0] f[i,1]=f[s1,0]+f[s2,0]+f[s3,0]+.....+f[sk,0]
AcWing 285. 没有上司的舞会 - AcWing

#include
using namespace std;
const int N = 6010;
int n;
int w[N];
int h[N], e[N], ne[N], idx;
bool st[N]; // 用来判断是否有父节点,查找根节点
int f[N][2];void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}void dfs(int u){f[u][1] = w[u];for (int i = h[u]; i != -1; i = ne[i]) { int j = e[i];dfs(j);f[u][0] += max(f[j][0], f[j][1]); // 状态转移f[u][1] += f[j][0];}
}int main(void)
{cin >> n ;for (int i &#61; 1 ; i <&#61; n ; i &#43;&#43;) cin >> w[i];memset(h, -1, sizeof h);for (int i &#61; 0; i < n - 1; i&#43;&#43;) {int a, b ;cin >> a >> b ;add(b, a);st[a] &#61; true;}int root &#61; 1;while (st[root]) root&#43;&#43;; //找到根节点dfs(root);cout << max(f[root][0], f[root][1]) << endl ;return 0;
}

记忆化搜索

顾名思义&#xff0c;就是把每一次搜索的过程中的有用信息都存下来&#xff0c;这样下一次搜索如果也要用到这个信息&#xff0c;就可以直接调用而不用再次搜索

AcWing 901. 滑雪 - AcWing

#include
using namespace std;const int N &#61; 310;
int n, m;
int h[N][N];
int f[N][N];int dx[] &#61; {-1, 0, 1, 0};
int dy[] &#61; {0, 1, 0, -1};int dp(int x, int y)
{int &v &#61; f[x][y]; // v 等价于 f[x][y]if (v !&#61; -1) return v; // 如果他已经被搜过了&#xff0c;直接返回值v &#61; 1; // 至少为1for (int i &#61; 0; i < 4; i&#43;&#43;) {int a &#61; x &#43; dx[i], b &#61; y &#43; dy[i];if (a >&#61; 1 && a <&#61; n && b >&#61; 1 && b <&#61; m && h[a][b] < h[x][y])v &#61; max(v, dp(a, b) &#43; 1);}return v;
}int main(void)
{scanf("%d %d", &n, &m);for (int i &#61; 1; i <&#61; n; i&#43;&#43;) {for (int j &#61; 1; j <&#61; m; j&#43;&#43;) {scanf("%d", &h[i][j]);}}memset(f, -1, sizeof f); // 表示每个状态都没有被算过int res &#61; 0;for (int i &#61; 1; i <&#61; n; i&#43;&#43;) {for (int j &#61; 1; j <&#61; m; j&#43;&#43;) {res &#61; max(res, dp(i, j));}}cout << res << endl ;return 0;
}

区间DP

区间dp &#xff0c;指在一段区间上进行动态规划&#xff0c;一般做法是由长度较小的区间往长度较大的区间进行递推&#xff0c;最终得到整个区间的答案&#xff0c;而边界就是长度为1以及2的区间。

282. 石子合并 - AcWing题库

#include
using namespace std;
const int N &#61; 310;
int n;
int s[N]; // 前缀和
int f[N][N];int main(void)
{cin >> n;for (int i &#61; 1; i <&#61; n; i&#43;&#43;) cin >> s[i], s[i] &#43;&#61; s[i - 1]; // 前缀和for (int len &#61; 2; len <&#61; n; len&#43;&#43;) { // 先枚举区间长度for (int i &#61; 1; i &#43; len - 1 <&#61; n; i&#43;&#43;) { // 再枚举区间左端点int j &#61; i &#43; len - 1;f[i][j] &#61; 1e8;for (int k &#61; i; k < j; k&#43;&#43;) { // 枚举区间内每一种合并方式求最小f[i][j] &#61; min(f[i][j], f[i][k] &#43; f[k &#43; 1][j] &#43; s[j] - s[i - 1]);}}}cout << f[1][n] << endl ;return 0;
}

计数DP

类比完全背包问题&#xff0c;前i个物品中任选且体积恰好为j的方案数f[i, j]&#xff0c;对第i个物品进行分集合&#xff0c;选一个第i个物品使得体积恰好为j就是f[i, j - i]&#xff0c;选两个第i个物品使得体积恰好为j就是f[i, j - 2i]&#xff0c;以此类推方案数就是总和
f[i,j]&#61;f[i−1,j]&#43;f[i,j−i]&#43;f[i,j−2∗i]&#43;f[i,j−3∗i]&#43;...&#43;f[i,j−s∗i]f[i, j] &#61; f[i - 1, j] &#43; f[i, j - i] &#43; f[i, j - 2 * i] &#43; f[i, j - 3 * i] &#43; ... &#43; f[i, j - s * i] f[i,j]&#61;f[i1,j]&#43;f[i,ji]&#43;f[i,j2i]&#43;f[i,j3i]&#43;...&#43;f[i,jsi]
利用完全背包优化方式&#xff1a;
f[i,j−i]&#61;f[i−1,j−i]&#43;f[i,j−2∗i]&#43;f[i,j−3∗i]&#43;...&#43;f[i,j−s∗i]f[i, j - i] &#61; f[i - 1, j - i] &#43; f[i, j - 2 * i] &#43; f[i, j - 3 * i] &#43; ... &#43;f[i, j - s * i] f[i,ji]&#61;f[i1,ji]&#43;f[i,j2i]&#43;f[i,j3i]&#43;...&#43;f[i,jsi]
可得&#xff1a;f[i,j]&#61;f[i−1,j]&#43;f[i,j−i]​f[i, j] &#61; f[i - 1, j] &#43; f[i, j - i]​f[i,j]&#61;f[i1,j]&#43;f[i,ji]

然后优化成一维空间&#xff0c;变成f[j]&#61;f[j]&#43;f[j−i]f[j] &#61; f[j] &#43; f[j - i]f[j]&#61;f[j]&#43;f[ji]即可

AcWing 900. 整数划分 - AcWing

#include
using namespace std;
const int N &#61; 1010, mod &#61; 1e9 &#43; 7;
int f[N];
int main(void)
{int n;cin >> n;f[0] &#61; 1;for (int i &#61; 1; i <&#61; n; i&#43;&#43;) {for (int j &#61; i; j <&#61; n; j&#43;&#43;) {f[j] &#61; (f[j] &#43; f[j - i]) % mod;}}cout << f[n] << endl ;return 0;
}


推荐阅读
  • Codeforces Round #566 (Div. 2) A~F个人题解
    Dashboard-CodeforcesRound#566(Div.2)-CodeforcesA.FillingShapes题意:给你一个的表格,你 ... [详细]
  • 本文探讨了如何在模运算下高效计算组合数C(n, m),并详细介绍了乘法逆元的应用。通过扩展欧几里得算法求解乘法逆元,从而实现除法取余的计算。 ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本题探讨了一种字符串变换方法,旨在判断两个给定的字符串是否可以通过特定的字母替换和位置交换操作相互转换。核心在于找到这些变换中的不变量,从而确定转换的可能性。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • Splay Tree 区间操作优化
    本文详细介绍了使用Splay Tree进行区间操作的实现方法,包括插入、删除、修改、翻转和求和等操作。通过这些操作,可以高效地处理动态序列问题,并且代码实现具有一定的挑战性,有助于编程能力的提升。 ... [详细]
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 文件描述符、文件句柄与打开文件之间的关联解析
    本文详细探讨了文件描述符、文件句柄和打开文件之间的关系,通过具体示例解释了它们在操作系统中的作用及其相互影响。 ... [详细]
  • 本文详细探讨了VxWorks操作系统中双向链表和环形缓冲区的实现原理及使用方法,通过具体示例代码加深理解。 ... [详细]
  • 本教程涵盖OpenGL基础操作及直线光栅化技术,包括点的绘制、简单图形绘制、直线绘制以及DDA和中点画线算法。通过逐步实践,帮助读者掌握OpenGL的基本使用方法。 ... [详细]
author-avatar
PHPdudu
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有