浏览器做单页网站项目互联网平面设计
news/
2025/9/26 15:52:01/
文章来源:
浏览器做单页网站项目,互联网平面设计,中文wordpress网站,wordpress 隐私策略目录
DP简介
01背包问题
采药(01背包例题)
完全背包
疯狂的采药(完全背包例题)
背包变式
装箱问题
砝码称重
质数拆分
优化思考 DP简介 全称Dynamic Programming即动态规划
DP算法是解决多阶段决策过程最优化问题的一种常用方法。
多阶段决策过程是指这样一类特…
目录
DP简介
01背包问题
采药(01背包例题)
完全背包
疯狂的采药(完全背包例题)
背包变式
装箱问题
砝码称重
质数拆分
优化思考 DP简介 全称Dynamic Programming即动态规划
DP算法是解决多阶段决策过程最优化问题的一种常用方法。
多阶段决策过程是指这样一类特殊的活动过程过程可以按时间顺序分解成若干个相互联系的阶段在每一个阶段都需要做出决策全部过程的决策是一个决策序列。
动态规划算法是解决多阶段决策过程最优化问题的一种常用方法难度比较大技巧性也很强。利用动态规划算法可以优雅而高效地解决很多贪婪算法或分治算法不能解决的问题。
有时遇到暴搜宽搜TLE、贪心分治不理想的情况时用动态规划常常能够起到出人意料的效果 01背包问题 01背包问题最经典的问题就是给一个背包让你从中选取n个物品且每个物品只能选一次求取在背包容量满足大于等于背包内物品总体积的情况下所能装的物品的最大价值或者最小价值在对于这种问题时我们常常利用数学集合的思想来解决
我们将背包当中的物品体积开一个v[N]数组价值开一个w[N]数组最后开一个dp二维数组
v[N]一维数组来存储每个物品的体积w[N]一维数组来存储每个物品的价值
dp[i][j]表示从i个物品当中选取且体积不超过j的选法因当第一种情况成立时返回值为0第二种情况成立时选取物品放入返回的是所选取物品的价值所以dp二维数组的返回值是此种选法情况的背包中物品的最大价值
对应每个dp[i][j]可以分为两种选择情况
第一种选择情况为从i - 1个物品当中选取且总体积不超过j的情况
第二种选择情况为从i个物品当中选取且总体积不超过j的情况
在对于dp二维数组的模拟过程之中我们发现第二种情况要用i来描述第一种情况要用i - 1描述二者不完全一致因此为了优化我们将第二种情况进行合理变式为从i - 1个物品当中选取且总体积不超过j - v[i]的情况
因此dp二维数组在依次枚举的时候就可以这样做变动
f[i][j] f[i - 1][j];//第一种情况
if(j v[i])f[i][j] max(f[i - 1][j],f[i - 1][j - v[i] w[i]);//第二种情况
两种情况求取最大值第二种情况的成立条件是第i件物品的体积小于背包体积
采药(01背包例题)
辰辰是个天资聪颖的孩子他的梦想是成为世界上最伟大的医师。为此他想拜附近最有威望的医师为师。医师为了判断他的资质给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说“孩子这个山洞里有一些不同的草药采每一株都需要一些时间每一株也有它自身的价值。我会给你一段时间在这段时间里你可以采到一些草药。如果你是一个聪明的孩子你应该可以让采到的草药的总价值最大。”如果你是辰辰你能完成这个任务吗
题目描述
第一行有 2 个整数 T和M用一个空格隔开T 代表总共能够用来采药的时间M 代表山洞里的草药的数目 接下来的 M行每行包括两个在1到 100之间包括 1 和 100的整数分别表示草药的时间和这株草药的价值。
输入
输出在规定的时间内可以采到的草药的最大总价值。
输出
输出在规定的时间内可以采到的草药的最大总价值
样例输入
70 3
71 100
69 1
1 2
样例输出
3
源代码
这道题目就是很经典的01背包问题换汤不换药而已。背包中的物品换做了草药背包的体积换作了最多能够使用的时间物品的体积换做了采取草药的时间
#include iostream
using namespace std;
const int N 300010;
int v[N];//存每株草药采取所花时间
int w[N];//存每株草药的价值
int T,M;
int dp[N][N];//存不同情况的不同最大价值
int main()
{cin T M;for(int i 1;i M;i )cin v[i] w[i];for(int i 1;i M;i ){for(int j 0;j T;j ){dp[i][j] dp[i - 1][j];if(j v[i])dp[i][j] max(dp[i - 1][j],dp[i - 1][j - v[i]] w[i]);}}cout dp[M][T];return 0;
}
优化后源代码
#include iostream
using namespace std;
const int N 300010;
int v[N];//存每株草药采取所花时间
int w[N];//存每株草药的价值
int T,M;
int dp[N];//存不同情况的不同最大价值
int main()
{cin T M;for(int i 1;i M;i )cin v[i] w[i];for(int i 1;i M;i ){for(int j T;j v[i];j -- ){dp[j] max(dp[j],dp[j - v[i]] w[i]);}}cout dp[T];return 0;
} 完全背包 简单来说就是01背包的变形其本质与01背包相似只是在完全背包当中每一个物品可以被选择无数次而不是只能够选择一次一般来说完全背包问题是要进行性优化的否则会TLE
疯狂的采药(完全背包例题)
题目描述
LiYuxiang 是个天资聪颖的孩子他的梦想是成为世界上最伟大的医师。为此他想拜附近最有威望的医师为师。医师为了判断他的资质给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说“孩子这个山洞里有一些不同种类的草药采每一种都需要一些时间每一种也有它自身的价值。我会给你一段时间在这段时间里你可以采到一些草药。如果你是一个聪明的孩子你应该可以让采到的草药的总价值最大。” 如果你是 LiYuxiang你能完成这个任务吗 此题和原题采药的不同点 1. 每种草药可以无限制地疯狂采摘。 2. 药的种类眼花缭乱采药时间好长好长啊师傅等得菊花都谢了
输入
输入第一行有两个整数分别代表总共能够用来采药的时间 t 和代表山洞里的草药的数目 m。 第2到第 (m1) 行每行两个整数第 (i1) 行的整数 ai, bi分别表示采摘第 i 种草药的时间和该草药的价值。
输出
输出一行这一行只包含一个整数表示在规定的时间内可以采到的草药的最大总价值
样例输入
70 3
71 100
69 1
1 2
样例输出
140
源代码(已优化)
#include iostream
using namespace std;
const int N 100000010;
int v[N];//存每株草药采取所花时间
int w[N];//存每株草药的价值
int T,M;
int dp[N];//存不同情况的不同最大价值
int main()
{cin T M;for(int i 1;i M;i )cin v[i] w[i];for(int i 1;i M;i ){for(int j v[i];j T;j ){dp[j] max(dp[j],dp[j - v[i]] w[i]);}}cout dp[T];return 0;
} 背包变式 装箱问题
题目描述
有一个箱子容量为V正整数0≤V≤20000同时有n个物品0n≤30每个物品有一个体积正整数。要求n个物品中任取若干个装入箱内使箱子的剩余空间为最小。
输入
1个整数表示箱子容量 1个整数表示有m个物品 接下来n行分别表示这n个物品的各自体积
输出
1个整数表示箱子剩余空间。
样例输入
24
6
8
3
12
7
9
7
样例输出
0
源代码
典型的完全背包问题只不过求取最大值换做了求取最小值简单变式即可
#include iostream
using namespace std;
const int N 100000010;
int v[N];//存物品的体积
int V,M;
int dp[N];//存不同情况的不同最大占用空间
int main()
{cin V M;for(int i 1;i M;i )cin v[i];for(int i 1;i M;i ){for(int j v[i];j V;j ){dp[j] max(dp[j],dp[j - v[i]] v[i]);}}cout V - dp[V];return 0;
}
砝码称重 题目描述
你有一架天平和 N 个砝码这 N 个砝码重量依次是 W1, W2, · · · , WN。 请你计算一共可以称出多少种不同的重量 注意砝码可以放在天平两边。
输入
输入的第一行包含一个整数 N。 第二行包含 N 个整数W1, W2, W3, · · · , WN。 对于 50% 的评测用例1 ≤ N ≤ 15。 对于所有评测用例1 ≤ N ≤ 100N 个砝码总重不超过 100000。
输出
输出一个整数代表答案。
样例输入
3
1 4 6
样例输出
10
源代码
[样例说明] 能称出的 10 种重量是1、2、3、4、5、6、7、9、10、11。 1 1 2 6 - 4(天平一边放 6另一边放 4) 3 4 - 1 4 4 5 6 - 1 6 6 7 1 6 9 4 6 - 1 10 4 6 11 1 4 6
此处的dp为状态01数组
#include iostream
using namespace std;
const int N 300010;
int f[N][N];
int w[N];
int n,sum 0,ans 0;
//sum为累加砝码的最大值即最大边界值
//无论砝码如何放置每个砝码只能使用一次且最小值一定大于等于1
int main()
{cin n;for(int i 1;i n;i )//输入n个砝码的值 {cin w[i];sum w[i];//累加最大边界值 }for(int i 1;i n;i )//外层循环砝码 {f[i][w[i]] 1;//首先将该砝码重量标记为一种情况 for(int j 1;j sum;j )//内层循环砝码值 {if(f[i - 1][j] 1)//若上层为1 {f[i][j] 1;//则继承此种成立情况//对于新加的砝码值进行左右标记 f[i][j w[i]] 1; f[i][abs(j - w[i])] 1;}}}for(int i 1;i sum;i )//扫描1~最大边界值的砝码值 {if(f[n][i] 1)ans ;//若为1则证明此砝码值可以整出来 }cout ans;return 0;
}
质数拆分
题目描述
2019可以被分解成若干个两两不同的素数请问不同的分解方案有多少种 注意分解方案不考虑顺序如 2 2017 2019 和 2017 2 2019 属于同一种方案。
输入
无
输出
55965365465060
样例输入
无
样例输出
55965365465060
源代码(已优化)
本题拉取素数优化的方法可以了解一下埃氏筛法与线性筛法
#include iostream
using namespace std;
const int N 300010;
int prime[N];
bool isprime[N];
int idx 0;
long long dp[N];
void init()//线性筛法拉取素数表
{for(int i 2;i 2019;i ){if(!isprime[i]){prime[ idx ] i;}for(int j 1;j idx i 2019 / prime[j];j ){isprime[i * prime[j]] 1;if(i % prime[j] 0)break;}}
}
int main()
{init();dp[0] 1;//注意 for(int i 1;i idx;i ){for(int j 2019;j prime[i];j -- ){dp[j] dp[j] dp[j - prime[i]];}}cout dp[2019];return 0;
} 优化思考 二维数组的开辟范围当然是限制性很大的所以利用dp二维数组并不能够用来表示当物品种类过大的情况那么动态规划的算法也就有了鸡肋性不过幸好我们可以将一维数组优化为二维数组优化的方式是将代码等价变形并减少非必要的元素遍历
当我们将dp数组的首坐标删去之后我们可以发现循环里面的
dp[i][j] dp[i - 1][j];变成了
dp[j] dp[j];
因此首行代码可以省去
根据第二行代码的情况进行减少数据遍历的优化当第二行的情况成立时j应该大于等于v[i]也就是说在从0~v[i] - 1的情况都是无意义的遍历因此的原本两种情况可以合并为一种情况
if(j v[i])dp[i][j] max(dp[i - 1][j],dp[i - 1][j - v[i]] w[i]);
换做
dp[j] max(dp[j],dp[j - v[i]] w[i]);
但是此时变形之后的一维数组相当于
dp[i][j] max(dp[i - 1][j],dp[i][j - v[i]] w[i]);
然而我们想要的是
dp[i][j] max(dp[i - 1][j],dp[i - 1][j - v[i]] w[i]);
所以我们要对于第二重循环的j进行改变
for(int i 1;i M;i )
{for(int j 0;j T;j ){dp[i][j] dp[i - 1][j];if(j v[i])dp[i][j] max(dp[i - 1][j],dp[i - 1][j - v[i]] w[i]);}
}
调整之后为
for(int i 1;i M;i )
{for(int j T;j v[i];j -- ){dp[j] max(dp[j],dp[j - v[i]] w[i]);}
}
谨记
第二重循环从大到小遍历之后的优化为01背包优化也就是
dp[i][j] max(dp[i - 1][j],dp[i - 1][j - v[i]] w[i]);
第二重循环从小到大的遍历为完全背包优化也就是
dp[i][j] max(dp[i - 1][j],dp[i][j - v[i]] w[i]);
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/918485.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!