题解
分析题意
题目要求计算在给定的菜品价格列表中,有多少种点菜方案使得总价恰好等于 uim 口袋里的钱。每种菜品只能点一次,且点菜方案的总价不能超过 uim 口袋里的钱。
状态转移方程
我们可以使用动态规划来解决这个问题。定义一个数组 dp[i]
表示总价为 i 时的点菜方案数。初始时,dp[0] = 1
,表示不选任何菜品的情况。
对于每一种菜品,我们可以选择是否将其加入点菜方案。如果选择加入,那么我们需要从总价中减去该菜品的价格,即 dp[i-a[j]]
,其中 a[j]
是第 j 种菜品的价格。因此,状态转移方程为:
dp[i] += dp[i-a[j]]
需要注意的是,由于每种菜品只能点一次,所以在遍历菜品时,需要从大到小遍历,避免重复计算。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=10001;
int n,m;
int a[N],dp[N];
int ans;
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=m;j>=a[i];j--){
dp[j]+=dp[j-a[i]];
}
}
cout<<dp[m];
return 0;
}
复杂度分析
时间复杂度: O ( N M ) O(NM) O(NM),其中 N N N 是菜品种类数, M M M 是 uim 口袋里的钱。因为我们需要遍历所有菜品和所有可能的总价。
空间复杂度: O ( M ) O(M) O(M),因为我们只需要存储总价为 0 0 0 到 M M M 的点菜方案数。