目录
前景提要:
(1)dp数组的含义:这个dp数组代表的意义是什么,[i][j]又分别代表什么意思
(2)dp数组的属性:包括最大值,最小值,方案数,次数,即dp数组本身存的数
(3)dp数组的初始化:根据它的含义进行合理的初始化
(4)dp数组的遍历顺序:是正序从前往后,还是后续遍历防止被重复覆盖
(5)dp数组的递推公式:从最后一步反推,即要得到这一步,需要上一步进行的操作
(6)dp数组的返回值:即题目要求的是dp数组的什么,要根据含义来
鸣人的影分身(线性DP)
思路解析:
透过题目看本质,这道题的本质是:
给出一个和,给出一个份数,求出“和”可以被分成多少个份数大小的集合
举个例子:总和为:7 份数为:3
那么就有:(注意顺序不同,集合内的数字相同被视为一种情况)
(7,0,0)
( 6,1,0)
(5,2,0) (5,1,1)
(4,3,0) (4,2,1)
(3,3,1) (3,2,2)
DFS解法
相信看完例子解释的你,已经想到了DFS,来暴力搜索
DFS代码如下:
DFS的核心之一就是参数的意义
(1)首先要输入总能量,和分身的数量
那么在向下搜索的过程中:
(2)思考深搜过程:
<1>需要一个标志变量,来标记当前从这个标志变量开始枚举,也就是变量start
这个就类似于(1~5)个数中(集合大小为3个数)的组合
<2>边界条件,当给被赋予能量的分身数量==给出的分身数量 且剩余能量为0
<3>剪枝,当枚举过程中,被赋予能量的分身数量大于给定的分身数量
#include<iostream>
using namespace std;
int m, n;
int res;
// t:剩余的能量 start:下一个分身的值 state:已经完成的分身
void dfs(int t, int start, int state)
{
if (state == n && t == 0)//已经完成的分身数量==n 且剩余的能量为0 即返回
{
res++;//记录数量
}
//可不写“==”
if (state >= n) return;//已经完成的分身数量>=n,也返回(就算还有剩余能量)
for (int i = start; i <= t; i++)
{
dfs(t - i, i, state + 1);//剩余的能量-i,下一个从i开始枚举,分身的数量++
}
}
int main()
{
int T;
cin >> T;
while (T--)
{
cin >> m >> n;
res = 0;
dfs(m, 0, 0);//初始剩余的能量为:m
cout << res << endl;
}
return 0;
}
DP(完全背包)
有没有一种可能这个是完全背包,即每个数可以被放入背包无限次
(1)dp数组的含义:总和为i,划分为j个数的所有情况
(2)dp数组的属性:符合题目条件的次数
(3)dp数组的递推公式:观察上面给出的例子可知:
对于最后一步有:划分为j个数情况:
<1>当i<j时,也就是必然有影子被分为0的情况
划分为j个数的情况==划分j-1个数的情况+最后一列放0的情况
<2>当i>=j时,有两种情况:
当最小的数为不为0的情况,那么方案数==总和i-j个1的情况+最小的数为0的情况
·······1:有影子被分到的最小能量为0(最小的数为0的情况被<1>处理了)
·······2:影子的被分到的最小能量不为0
(4)dp数组的初始化:由递推公式可知:dp[i][0]的情况都是1
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 11;
int main()
{
int T;
scanf("%d", &T);
while (T -- )
{
int n, m;
scanf("%d%d", &m, &n);
int f[N][N] = {0};//dp数组的含义:总和为i,划分为j个数的所有情况
f[0][0] = 1;//当总数为0,划分为0个,情况数为:1
/*问题:
for(int i=0;i<m;i++)
f[i][0]=1;*/
for (int i = 0; i <= m; i ++ )
for (int j = 1; j <= n; j ++ )
{
f[i][j] = f[i][j - 1];//划分为j个数的情况==划分j-1个数的情况+最后一列放0的情况
if (i >= j) f[i][j] += f[i - j][j];//当最小的数为不为0的情况,那么方案数==总和i-j个1的情况+最小的数为0的情况
}
printf("%d\n", f[m][n]);
}
return 0;
}
思维解法递归解法
转换为:n个苹果放m个盘的经典问题
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int f(int x,