一开始我使用DFS的做法,原因是最近一段时间联系DFS比较多,所以感觉比较熟悉,
dfs代码如下:
#include<algorithm>
#include<cstring>
#include<vector>
#include<stack>
#include<queue>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstdlib>
using namespace std;
int n,m;
const int N=1e5;
int q[N];
int mon,res;
int w;
void dfs(int mon,int step)
{
if(mon==m) //递归出口
{
res++;
return;
}
if(step==n)//没有可选的菜了
return;
if(m-mon>=q[w])
{
//选这个菜
dfs(mon+q[step],step+1);
//不选这个菜
dfs(mon,step+1);
}
}
int main(int argc,char **argv)
{
//输入
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>q[i];
}
//解决
sort(q,q+n);
dfs(0,0);
//输出
cout<<res;
getchar();//防止vsc中的黑窗闪退
return 0;
}
结果做出来之后,发现卡了一个,如图:
可想而知,递归的风险还是有的,一个是牺牲了相当大的空间,另一个问题是处理的时间较多。
所以采用线性dp的做法:
要注意状态转移方程的思考
//dp要注意状态转移方程的书写
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
int n,m;
const int N=1e3;
int q[N],res[N][N];
int dp()
{
//i和j从1开始写,防止溢出现象
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
//三个状态转移方程(递推式)
if(j==q[i])
res[i][j]=res[i-1][j]+1;
if(j>q[i])
res[i][j]=res[i-1][j]+res[i-1][j-q[i]];
if(j<q[i])
res[i][j]=res[i-1][j];
}
}
}
int main(int argc,char **argv)
{
//input
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>q[i];
//solve
dp();
//output
cout<<res[n][m];
return 0;
}
AC!