数字的组合(背包方案)
问题 AH: 【基础】数字的组合
题目描述
给定N个正整数A1,A2,…,AN,从中选出若干个数,使它们的和为M,求有多少种选择方案。
注意:选择不同位置的,但值相同的数,认为是不同的方案。
比如:有3个数1 1 1,要组合出2,那么有3个方案,分别是选第1、2个数,选第1、3个数,选第2、3个数。
输入
第一行包含两个整数N和M。
第二行包含N个整数,表示A1,A2,…,AN。
数据范围
1≤N≤100,
1≤M≤10000,
1≤Ai≤1000
输出
包含一个整数,表示可选方案数(本题的计算结果一定在int范围内)。
样例输入
4 4
1 1 2 2
样例输出
3
分析
虽然做出来了,但是状态转移方程是凑出来的,没有很好理解,所以写出来重新整理一下思路.
本题求恰好装满M
容量的方案数,以此每个状态dp[i][j]
表示为前i
个物品恰好装满j
容量的方案数量,那么边界为dp[0][0] = 1
第0
个物品恰好需要0
容量的方案数为1
,那么对于第i
个物品,有两种状态,第一种:选择第i
个物品,那么方案数等于dp[i-1][j-a[i]]
前i-1
个物品恰好使用j-a[i]
容量的方案数 ; 第二种状态是不选择物品i
,那么它的方案数就等于dp[i-1][j]
,前i-1
物品恰好使用j
容量的方案数.假如a[i] = 6
,那么dp[i][6] = dp[i-1][0]
,而dp[i-1][0] = dp[i-2][0] = .... = dp[0][0] = 1
,也就是如果容量恰好等于第i
个物品的花费,那么可以直接选择它,方案数为1
,不用专门初始化,那对于出现多次相同花费的方案a[i] = a[j] = a[k] = 6
的话,dp[k][6] = dp[k-1][0](选择k) + dp[k-1][6](不选)
,而不选k的方案就包括前面选择i
和j
的两种情况,所有是可以计算所有选择方案的
代码
int a[105];
int dp[105][10005];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
//
// freopen("E:/Code/C++/untitled1/input.txt","r",stdin);
// freopen("output.txt","w",stdout);
int n,m;
cin >> n >> m;
//memset(dp,-1,sizeof(dp));
f(i,1,n+1) cin >> a[i];
dp[0][0] = 1; //初始化
for(int i = 1;i <= n;++i)
for(int j = 0;j <= m;++j)
if(j >= a[i]) dp[i][j] = dp[i-1][j] + dp[i-1][j-a[i]]; //选择i的方案 + 不选
else dp[i][j] = dp[i-1][j];
cout << dp[n][m];
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战