十分经典的一道DP题。
转移方程式为:
f[j]+=f[j-a[i]];
我们首先定义
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前
i
i
i个菜品恰好花费
j
j
j元的方案数。
当我们买第
i
i
i道菜时:
f[i][j]+=f[i-1][j-a[i]];
当我们不买第 i i i道菜时:
f[i][j]+=f[i-1][j];
但当第
i
i
i道菜的价格被就是
j
j
j时,就可以只买自己,这种情况应该其实包含在
1
1
1中,但是由于
f
[
i
]
[
0
]
=
0
f[i][0]=0
f[i][0]=0,所以不会算入这种情况。所以我们就要把
f
[
i
]
[
0
]
f[i][0]
f[i][0]刚开始就赋值为
1
1
1。
代码
#include <bits/stdc++.h>
using namespace std;
int n,m,a[105],f[105][10005];
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++) f[i][0]=1;//注意0
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
f[i][j]+=f[i-1][j];
if(j>=a[i]) f[i][j]+=f[i-1][j-a[i]];
}
}
printf("%d",f[n][m]);
return 0;
}
我们可以优化为一维。
但我们的第二重循环必须逆序跑,因为我们一维的转移方程式为:
f[j]+=f[j-a[i]];
如果跑正序,我们的 f [ j ] f[j] f[j]还没有更新, f [ j − a [ i ] ] f[j-a[i]] f[j−a[i]]反倒先更新了,这样的话与题意的“每种菜只有一份”相冲。如果没有这句话,我们就可以正序了。
#include <bits/stdc++.h>
using namespace std;
int n,m,a[105],f[10005];
int main() {
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
f[0]=1;
for(int i=1;i<=n;i++) {
for(int j=m;j>=a[i];j--)
f[j]+=f[j-a[i]];
}
printf("%d",f[m]);
return 0;
}
( 1 ) i f ( j = = 第 i 道 菜 的 价 格 ) f [ i ] [ j ] = f [ i − 1 ] [ j ] + 1 ; (1)if(j==第i道菜的价格)\ f[i][j]=f[i-1][j]+1; (1)if(j==第i道菜的价格) f[i][j]=f[i−1][j]+1;
( 2 ) i f ( j > 第 i 道 菜 的 价 格 ) f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − 第 i 道 菜 的 价 格 ] ; (2)if(j>第i道菜的价格)\ f[i][j]=f[i-1][j]+f[i-1][j-第i道菜的价格]; (2)if(j>第i道菜的价格) f[i][j]=f[i−1][j]+f[i−1][j−第i道菜的价格];
( 3 ) i f ( j < 第 i 道 菜 的 价 格 ) f [ i ] [ j ] = f [ i − 1 ] [ j ] ; (3)if(j<第i道菜的价格)\ f[i][j]=f[i-1][j]; (3)if(j<第i道菜的价格) f[i][j]=f[i−1][j];
说的简单一些,这三个方程,每一个都是在吃与不吃之间抉择。若钱充足,办法总数就等于吃这道菜的办法数与不吃这道菜的办法数之和;若不充足,办法总数就只能承袭吃前 i − 1 i-1 i−1道菜的办法总数。依次递推,在最后,我们只要输出 f [ n ] [ m ] f[n][m] f[n][m]的值即可。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,a[105],f[105][10005];
int main() {
scanf("%d %d",&n,&m);
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;
else if(j>a[i]) f[i][j]=f[i-1][j]+f[i-1][j-a[i]];
else f[i][j]=f[i-1][j];
}
}
printf("%d",f[n][m]);
return 0;
}