动态规划
0.介绍
动态规划(Dynamic Program,DP)和分治方法核心差不多,将一个复杂的问题分解为相对简单的子问题,最后得出答案。但是分冶法子问题是相对独立无关的,而动态规划子问题前后相关,而且非常相似处理方法几乎一样。所以可以把前面的子问题的计算结果记录为一种"状态",后面子问题直接查找前面得到的状态避免了重复计算
DP题有三步:定义状态,状态转移,算法实现
DP可以分成线性和非线性的:
1.线性DP:顺推与逆推,常用表格来处理状态
2.非线性DP:例如树形DP,建立在树上。
可以通过根到叶,根传给有用信息给子节点
可以通过叶到根,根的子节点给有用的信息给根
1.基础DP
介绍
基础DP问题直观易于理解,状态容易,表示转移方程容易得到
例题
1.1硬币问题
Coin Change [HDU - 2069]
假设有5种硬币:50美分,25美分,10美分,5美分和1美分。 我们希望以给定的金额使用这些硬币进行更改。
例如,如果我们有11美分,则可以用一枚10美分硬币和一枚1美分硬币,或两枚5美分硬币和一枚1美分硬币,或一枚5美分硬币和六枚1美分硬币进行找零。 分硬币或11个1分硬币。 因此,使用上述硬币,有四种方法可以使11分钱找零。 请注意,我们认为有一种方法可以使零美分发生变化。
编写一个程序,以查找以美分计的任何金额进行更改的不同方式的总数。 您的程序应该能够处理多达100个硬币。
输入
输入文件包含任意数量的行,每行包含一个数字(≤250),以分币为单位。
输出
对于每条输入线,输出一条线,其中包含使用上述5种硬币进行更改的不同方式的数量。
样本输入
11
26
样本输出
4
13
思路
- 思路递归从后往前,但有很多重复部分
- 所以从前往后打表
- 若没有100总硬币的需求,那只要2个循环打表DP[j] = DP[j] + DP[j - type[i]];(type是钱币种类)就行
- 将DP设为二维数组,横坐标i为钱的总数纵坐标j为钱币量的数,若i能用j个钱币表示则DP[i][j]=1;
- 数组大小开为DP[251][101];
钱的限制*币数限制
代码
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
const int maxn = 1e5 + 10;
#define re(x) for(int i=0;i<x;++i)
#define rey(x) for(int j=0;j<x;++j)
#define Cheak(x,y) (x<W&&x>=0&&y>=0&&y<H)
typedef long long LL;
using namespace std;
int dir[4][2] = {
{
-1,0},{
0,-1},{
1,0},{
0,1} };
int T, n, a[maxn], m, * p, flag = 1;
int type[5] = {
1,5,10,25,50 }, DP[251][101] = {
0 };
int main()
{
ios::sync_with_stdio(0); cin.tie(0);
DP[0][0] = 1;
re(5) {
for (int j = 1; j < 101; j++)
{
for (int k = type[i]; k < 251; k++)
DP[k][j] += DP[k - type[i]][j - 1];
}
}
int ans[251] = {
0 };
re(251)
rey(101)
ans[i] += DP[i][j];
while (cin>>n)
cout << ans[n]<<endl;
}
1.2 0/1背包
有一个人被称为“骨收集者带着V的体积的背包收集骨头的过程中,有很多骨头,显然,不同的骨头具有不同的价值和不同的体积,现在给定骨头在行进过程中的价值,您能算出吗?骨收集器能获得的总价值的最大值是多少?
输入
第一行包含一个整数T,即个案数。
紧随其后的是T个案例,每个案例三行,第一行包含两个整数N,V(N <= 1000,V <= 1000),它们表示骨头的数量和包的体积。第二行包含代表每个骨骼值的N个整数。第三行包含N个整数,代表每个骨骼的体积。
输出
每行一个整数,代表总和的最大值(该数字将小于231)。
样本输入
1
5 10
1 2 3 4 5
5 4 3 2 1
样本输出
14
思路
- 设一个二维数组dp[i][j],j代表所用空间,i代表物品序号
- 只装第一个时,i=1,j从第一个重量开始,无论占多少重量,都是一个价值
- 然后装第二个,如果比上一行的减它重量的列加它价值还高的话,该列刷新成新的价值,相当于第一第二都放进去了
- 因为下一行只于上一行有关,所以不需要二维数组(当不需要知道放的是什么时)
代码
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
const int maxn = 1e5 + 10;
#define re(x) for(int i=0;i<x;++i)
#define rey(x) for(int j=0;j<x;++j)
#define Cheak(x,y) (x<W&&x>=0&&y>=0&&y<H)
typedef long long LL;
using namespace std;
int dir[4][2] = {
{
-1,0},{
0,-1},{
1,0},{
0,1} };
int T, n, a[maxn], m, * p