dp洛谷1164:
思路一正常递归:
//dp解决
#include <bits/stdc++.h>
using namespace std;
/*int read()
{
int k;
scanf("%d",&k);
return k;
}*/
int f[105][10005];//定义f[i][j]为对前i种物品用光j的钱的方案数量
int m,n;
int a[105];
int main ()
{
scanf("%d%d",&n,&m);
//m=read(),n=read();
//for(int i=1;i<=n;i++)
//{
// a[i]=read();
//}
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
//对每种情况考虑取与不取
if(j==a[i])f[i][j]=f[i-1][j]+1;//1:恰好花光
if(j>a[i])f[i][j]=f[i-1][j-a[i]]+f[i-1][j];
if(j<a[i])f[i][j]=f[i-1][j];
}
}
printf("%d",f[n][m]);
return 0;
}
思路2:01背包
dp[i][j]表示前i个菜品恰好花费j元的方案数
# include <bits/stdc++.h>
using namespace std;
int dp[105][10005];
int n,m;
int a[105];
int main ()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=0;i<=n;i++)dp[i][0]=1;//恰好花光情况下,从j=0状态转移,即方案为1种
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
dp[i][j]+=dp[i-1][j];
if(j>=a[i])
dp[i][j]+=dp[i-1][j-a[i]];
}
}
printf("%d",dp[n][m]);
return 0;
}
思路三:记忆化搜索
设f(i,j)表示当前选中了第i道菜(必须选),还剩j块前。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL f[105][10005],n,m,v[105],ans;
LL dfs(LL c,LL k)
{
if(f[c][k])return f[c][k];
if(v[c]>k)return 0;
if(v[c]==k)return 1;
for(LL i=c+1;i<=n;i++)f[c][k]+=dfs(i,k-v[c]);
return f[c][k];
}
int main()
{
scanf("%lld%lld",&n,&m);
for(LL i=1;i<=n;i++)scanf("%lld",&v[i]);
for(LL i=1;i<=n;i++)ans+=dfs(i,m);
printf("%lld\n",ans);
return 0;
}