简单dp问题汇总
简单dp问题总共分为四类:找钱问题,01背包问题,最长公共子序列问题,最长递增子序列问题
------------------------------------------------------------------------------------------------------------------------------------------
找钱问题
这类问题是dp中最基础的问题,其形式是最外层循环为钱的种类,第二层是钱的金额,最末层是用多少数量的钱实现
但是核心是建立在后续能用前面的值推出的基础上。
dp[j][k] = dp[j][k] + dp[j - 1][k - money[i]];
j表示用多少张钱,k表示目前的金额
这种问题要先知道可用的钱币是什么,然后先把他存在数组里
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 int money[5] = { 1,5,10,25,50 }; 5 long long int dp[300][300] = {0}; 6 int ans[300] = {0}; 7 int main() 8 { 9 int n; 10 memset(dp, 0, sizeof(dp)); 11 dp[0][0] = 1;//切记是从dp[0][0]开始的 12 for (int i = 0; i < 5; i++) 13 { 14 for (int j = 1; j <= 100; j++) 15 { 16 for (int k = money[i]; k <252; k++)//之前开太大了,爆栈 17 { 18 dp[j][k] = dp[j][k] + dp[j - 1][k - money[i]]; 19 20 } 21 } 22 } 23 24 for (int i = 0; i <252; i++) 25 { 26 ans[i] = 0; 27 for (int j = 0; j <= 100; j++) 28 { 29 ans[i] += dp[j][i]; 30 } 31 } 32 while (cin >> n) cout << ans[n] << endl; 33 return 0; 34 }
------------------------------------------------------------------------------------------------------------------------------------------
0/1背包问题
这问题核心就是控制背包容量,然后问当前物品装还是不装的问题
纵向是第几个物品
横向是背包容量
dp[j][k] = max(dp[j - 1][k], dp[j - 1][k - bone[j].volume] + bone[j].value);
不装就和前一个情况一样,装就要在当前背包容量减去所要装的骨头体积的情况下再加上此骨头的价值
1 #include <cstdlib> 2 #include <cctype> 3 #include <iterator> 4 #include <vector> 5 #include <cstring> 6 #include <cassert> 7 #include <map> 8 #include <queue> 9 #include <set> 10 #include <stack> 11 #include <stdio.h> 12 #define ll long long 13 #define INF 0x3f3f3f3f 14 #define ld long double 15 const ld pi = acos(-1.0L), eps = 1e-8; 16 using namespace std; 17 int dp[1010][1010]; 18 struct Bone 19 { 20 int value, volume; 21 }; 22 Bone bone[1010]; 23 int main() 24 { 25 ios::sync_with_stdio(false); 26 cin.tie(0); 27 int n; 28 cin >> n; 29 for (int i = 1; i <= n; i++) 30 { 31 memset(dp, 0, sizeof(dp)); 32 int num, volume; 33 cin >> num >> volume; 34 for (int j = 1; j <= num; j++) cin >> bone[j].value; 35 for (int j = 1; j <= num; j++)cin >> bone[j].volume; 36 37 for (int j = 1; j <= num; j++) 38 { 39 for (int k = 0; k <= volume; k++) 40 { 41 if (bone[j].volume > k)dp[j][k] = dp[j - 1][k];//如果当前骨头都比被背包大的话,那肯定不能放进去的 42 else dp[j][k] = max(dp[j - 1][k], dp[j - 1][k - bone[j].volume] + bone[j].value); 43 } 44 } 45 46 cout << dp[num][volume] << endl; 47 } 48 }
------------------------------------------------------------------------------------------------------------------------------------------
最长公共子序列问题
感觉这个可以背下来
遍历一下,如果元素相同,就找dp[i-1][j-1]的那个值+1;
否则就找dp[i][j-1]和dp[i-1[j]中最大的
1 #include <iostream> 2 #include <cmath> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 using namespace std; 7 int dp[1005][1005]; 8 string s1, s2; 9 int main() 10 { 11 12 while (cin >> s1 >> s2) 13 { 14 memset(dp, 0, sizeof(dp)); 15 for (int i = 1; i <= s1.size(); i++) 16 { 17 for (int j = 1; j <= s2.size(); j++) 18 { 19 if (s1[i - 1] == s2[j - 1]) 20 { 21 dp[i][j] = dp[i - 1][j - 1] + 1; 22 } 23 else 24 { 25 dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 26 } 27 } 28 } 29 cout << dp[s1.size()][s2.size()] << endl; 30 } 31 }
------------------------------------------------------------------------------------------------------------------------------------------
最长递增子序列
用两个循环定位
第一个循环定位当前值i
第二个循环依次循环j从开始到当前值,只要该值比当前固定的值(第一层循环)小,
那么就检查以它为结尾的最长递增子序列长度是多少,找出最长的那个子序列长度,
dp[i] = maxi + 1;
1 #include <iostream> 2 using namespace std; 3 int st[10000]; 4 int dp[10000] = { 0 }; 5 int main() 6 { 7 int n; 8 cin >> n; 9 for (int i = 1; i<=n; i++) cin >> st[i]; 10 dp[1] = 1;//第一个数最长只能为1 11 int ans = 1; 12 for (int i = 2; i <= n; i++) 13 { 14 int maxi = 0; 15 for (int j = 1; j < i; j++) 16 { 17 if (dp[j] >maxi &&st[j]>st[i]) maxi = dp[j]; 18 } 19 dp[i] = maxi + 1;//如果该数前面的数都不满足,那么他的长度就是1,从他自己开始 20 if (dp[i] > ans) ans = dp[i];//找出最大的 21 } 22 cout << ans << endl; 23 }
原文地址:https://www.cnblogs.com/Knightero/p/12720895.html
- 使用Identity Server 4建立Authorization Server (2)
- 使用Identity Server 4建立Authorization Server (1)
- Java之异常处理
- 挖洞经验 | 看我如何利用SAML漏洞实现Uber内部聊天系统未授权登录
- 使用ichartjs生成图表
- 使用angular4和asp.net core 2 web api做个练习项目(四)
- list.add(),向List集合插入对象报空指针异常
- 使用angular4和asp.net core 2 web api做个练习项目(三)
- 即学即用系列一:纯函数
- Java之StringBuffer,StringBuilder,Math,Date,SimpleDateFormat,UUID,File
- React编程思想
- 前台分页,以及类别选择
- 使用angular4和asp.net core 2 web api做个练习项目(二), 这部分都是angular
- 数据库 105道题目整理与吐血总结
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- AsyncTask类实例详解
- Android中ListView的item点击没有反应的解决方法
- android 应用内部悬浮可拖动按钮简单实现代码
- 详解Android PopupWindow怎么合理控制弹出位置(showAtLocation)
- Android Studio 3.0上分析内存泄漏的原因
- Android 实现图片生成卷角和圆角缩略图的方法
- Android使用TextInputLayout创建登陆页面
- Android使用WebSocket实现多人游戏
- Android Studio多渠道打包套路
- Vue路由History模式分析
- Android开发调用WebService的方法示例
- Js中Array对象
- 享元模式
- 两两交换链表中的节点
- 模板方法模式