输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目。接下来的n行,每行有一个1到40之间的正整数,分别给出a1,a2……an的值。
输出不同的选择物品的方式的数目。
3 20 20 20
3
#include<iostream>
using namespace std;
int count=0;
int n;
void dp(int a[],int p,int num)
{
if(num==0)
{
count++;return;
}
for(int i=p;i<n;i++)
{
if(a[i]<=num)
dp(a,i+1,num-a[i]);
}
}
int main()
{
cin>>n;
int a[n];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
dp(a,0,40);
cout<<count<<endl;
return 0;
} #include <iostream>
#include <memory.h>
using namespace std;
int count;
int st2[40];
int n;
void depth(int sum,int position){
if(sum>40)
return;
if(sum==40){
count++;
return;
}
for(int i=position;i<n;i++)
depth(sum+st2[i],i+1);
}
int main(){
while(cin>>n){
for(int i=0;i<n;i++)
cin>>st2[i];
count=0;
depth(0,0);
cout<<count<<endl;
}
return 0;
}
def findCountsNum(tempSum,nowIndex): #通过当前的下标和前面加的数字和进行查找
if nowIndex >= num:
return
if tempSum + digitNums[nowIndex] == 40:
global count
count += 1
findCountsNum(tempSum,nowIndex+1)
elif tempSum+digitNums[nowIndex] < 40:
findCountsNum(tempSum+digitNums[nowIndex],nowIndex+1)
findCountsNum(tempSum,nowIndex+1)
while True:
try:
num = int(input())
digitNums = []
for i in range(num):
digitNums.append(int(input()))
digitNums.sort()
count = 0
findCountsNum(0,0)
print(count)
except Exception:
break
//动态规划
//具体思想:对于数字dp[i][j],i代表编历到第i个有序数,总重量为j的方式数目
//dp[i][j]的值只可能来自两个,一是继承自dp[i-1][j],此时是代表第i个有序数没有用到
//二是由dp[i-1][j-q[i]],q[i]代表第i个有序数,此时是用到了第i个有序数
//注意实现方式,我设-1为不可达,需要判断以上两种情况,加成需要判断四种情况
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
vector<int> Q;
for(int i=0;i<n;i++)
{
int tmp;
cin>>tmp;
if(tmp<=40&&tmp>0) //读数,筛选出小于等于40的值
Q.push_back(tmp);
}
int m=Q.size();
sort(Q.begin(),Q.end()); //排序
int dp[m+1][41]; //动态规划数组
for(int i=0;i<41;i++)
dp[0][i]=-1; // 0个物品只有0可达,其余不可达。
dp[0][0]=1;
for(int i=1;i<=m;i++)
{
int tmp=Q[i-1];
for(int j=0;j<41;j++)
{
if(j-tmp<0) //j小于tmp的只能继承自dp[i-1][j];
{
dp[i][j]=dp[i-1][j];
}
else
{
if(dp[i-1][j]==-1&&dp[i-1][j-tmp]==-1) //四种情况,两个数值的存在不存在
dp[i][j]=-1;
else if(dp[i-1][j]!=-1&&dp[i-1][j-tmp]==-1)
dp[i][j]=dp[i-1][j];
else if(dp[i-1][j]==-1&&dp[i-1][j-tmp]!=-1)
dp[i][j]=dp[i-1][j-tmp];
else
dp[i][j]=dp[i-1][j]+dp[i-1][j-tmp];
}
}
}
if(dp[m][40]==-1) cout<<"0"<<endl; //不存在输出0
else cout<<dp[m][40]<<endl; //存在输出
}
}
#include<stdio.h>
#include<string.h>
int main(){
int target[41], i, j, volume[20], n;
while(scanf("%d", &n) != EOF){
for(i=0; i<n ; ++i)
scanf("%d", &volume[i]);
memset(target, 0, sizeof(int)*41);
target[0] = 1;
for(i=0 ; i<n ; ++i)
for(j=40; j>=volume[i] ; --j)
target[j] = target[j] + target[j-volume[i]];
printf("%d\n", target[40]);
}
return 0;
} 法一 :递归 把物品数目n和物品体积数组a[100]设为全局变量; count(i,sum)表示从数组的第i个数开始往后统计的组合数和为sum的种类数, sum为组合数的和,则:cout(i,sum)=cout(i+1,sum-a[i])+cout(i+1,sum), 其中cout(i+1,sum-a[i])表示包含了a[i],即为从第i+1个数开始往后统计 组合数的和为sum-a[i]的种类数, 而cout(i+1,sum)表示不包含a[i], 即为从第i+1个数开始往后统计组合数的和为sum的种类数 *********************************** #include<iostream> using namespace std; int a[100]; int n=1; int count(int i,int sum) { if(sum==0){return 1;} //找到一组和为sum的组合数; if(i==n||sum<0) return 0;//i==n说明没有其他的数来组合,sum<0说明组合不出; return count(i+1,sum-a[i])+count(i+1,sum);//从数组的第i为开始,包含a[i],和不包含; } int main() { while(cin>>n){ for(int i=0;i<n;i++) cin>>a[i]; cout<<count(0,40)<<endl; } return 0; }
法二:动态规划
#include<iostream>
using namespace std;
#define N 100
int n,a[N];
int main()
{
while(cin>>n){
int (*dp)[50]=new int[N][50];//dp[i][j]表示从前i个物品中凑出体积j;
for(int i=1;i<=n;i++)
{
cin>>a[i];
dp[i][0]=1; //初始边界
}
dp[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=40;j++)
{
dp[i][j]=dp[i-1][j];
if(a[i]<=j)
dp[i][j]+=dp[i-1][j-a[i]];
}
cout<<dp[n][40]<<endl;
delete []dp;
}
return 0;
}
******************************************************************
***************************************************************** 法三:动态规划,对值域空间-即对容积的可达性进行动态 规划。定义一维数组 int dp[N];
依次放入物品,计算每次放入物品可达的容积, 并在相应空间设置记录,最后判断dp[40] 是否可达 ,到达了几次
#include<iostream>
using namespace std;
#define N 100
int n,a;
int main()
{
while(cin>>n){
int *dp=new int[N];//dp[j]表示凑出体积i的次数;
for(int i=1;i<=n;i++)
{
cin>>a;
for(int j=40;j>=1;j--) //逆序,不然重复更新
if(dp[j]>0&&j+a<=40)
dp[j+a]+=dp[j];//如果j有dp[j]种方式可达,则每种方式加上a就可达j+a
dp[a]++;
}
cout<<dp[40]<<endl;
delete []dp;
}
return 0;
}
本题采用递归思想:
①物品n个,物品体积逐一放入a[100]中
②递归函数count(i,sum)=count(i+1,sum-a[i])+count(i+1,sum);
其中,i为第i个物品,sum代表剩余空缺体积数
count(i+1,sum-a[i]) 代表从第i+1个物品开始,剩余体积数为sum-a[i]的方案数
(隐含:已经将a[i]的体积计算进去,即包含a[i]的体积)
count(i+1,sum) 代表从第i+1个物品开始,剩余体积数为sum的方案数
(隐含:不将a[i]的体积计算进去,即不包含a[i]的体积)
代码如下:
#include<stdio.h>
int a[100];
int n=1;
int count(int i,int sum){ //递归函数
if(sum==0) return 1;
if(i==n||sum<0) return 0;
return count(i+1,sum-a[i])+count(i+1,sum);
}
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++) scanf("%d",&a[i]);
printf("%d",count(0,40));
}
return 0;
}
/*dp[i]指口袋体积为i时,共有几种方法
对于所有物品进行遍历,该物体体积为volume[i]
*/
//用滚动数组法,每次状态转移仅仅根据前一行数组决定,故选择用一维数组
#include<cstdio>
int volume[21];
int dp[41];
int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
for (int i = 1; i<=n; i++) //输入物品的体积
scanf("%d", &volume[i]);
for(int i = 1; i<=n; i++) //对于所有物品进行遍历,该物体体积为volume[i]
{
for(int j = 40; j>=volume[i]; j--) //j>=volume[i]因为dp[j]只能从0~40-volume[i]的状态转移而来
{
dp[j] += dp[j-volume[i]]; //如果dp[j]已经有了x种方法,而dp[j-volume[i]]也有y种方法
} //那么由于物体i的存在,对于体积为j的口袋,又能多出dp[j-volume[i]]种方法
//例如j=20,volume=10,而有5种方法能装满体积为10的口袋,那么只要有体积为10的物体就一定多出5种装满体积为20的口袋的方法
dp[volume[i]]++;//显而易见,当口袋体积等于该物体体积时,必然有一种方法
} //而可能不止一个物体有这样的体积,所以每次碰到这个体积的物体,就做一次++运算
printf("%d\n",dp[40]);
}//while
return 0;
}
#include <stdio.h>
#define N 801
int main()
{
int a, n;
int method[N];//method[i]表示i有几种凑法
while(scanf("%d", &n)!=EOF)
{
for(int i=0; i<N; i++)
{
method[i]=0;
}
method[0]=1;
for(int i=0; i<n; i++)
{
scanf("%d", &a);
for(int j=N-1; j>=a; j--)
{
method[j]+=method[j-a];
}
}
printf("%d\n", method[40]);
}
return 0;
}
#include<iostream>
using namespace std;
//方法一:递归
int count(int n, int*& a, int i, int sum)
{
if (sum == 0)
return 1; //找到一组和为sum的组合数;
if (i == n || sum < 0)
return 0;//i==n说明没有其他的数来组合,sum<0说明组合不出;
//从数组的第i为开始,包含a[i],和不包含a[i];
return count(n, a, i + 1, sum - a[i]) + count(n, a, i + 1, sum);
}
void recursion(int n)//递归
{
int* a = new int[n];
for (int i = 0; i < n; i++)
cin >> a[i];
cout << count(n, a, 0, 40) << endl;
delete[] a;
}
//法二:动态规划,对物品组成的体积进行动态规划。
void dynamic(int n)
{
int* a = new int[n + 1];
int(*dp)[41] = new int[n + 1][41];//dp[i][j]表示从前i个物品中凑出体积j;
for (int i = 0; i < 41; i++)
dp[0][i] = 0;//初始边界:从前0个里凑不出任何体积
for (int i = 1; i <= n; i++)
{
cin >> a[i];
dp[i][0] = 1; //初始边界:随便从前几个都能凑出0体积
}
dp[0][0] = 1;//初始边界:0可以凑出0
for (int i = 1; i <= n; i++)
for (int j = 1; j <= 40; j++)
{
dp[i][j] = dp[i - 1][j];
if (a[i] <= j)
dp[i][j] += dp[i - 1][j - a[i]];
}
cout << dp[n][40] << endl;
delete[] a, dp;
}
//法三:动态规划,对容积的可达性进行动态规划。
void dynamic_2(int n)
{
int a;
int* dp = new int[41];//dp[i]表示凑出体积i的次数;
for (int i = 1; i <= 40; i++)
dp[i] = 0;//初始边界:开始所有体积都没被凑出
for (int i = 1; i <= n; i++)
{
cin >> a;
for (int j = 40; j >= 1; j--) //逆序,否则要重复更新
if (dp[j] > 0 && j + a <= 40)
dp[j + a] += dp[j];//如果j有dp[j]种方式可达,则每种方式加上a就可达j+a
dp[a]++;
}
cout << dp[40] << endl;
delete[] dp;
}
int main()
{
int n;
while (cin >> n)
{
//recursion(n);
//dynamic(n);
dynamic_2(n);
}
return 0;
} #!/usr/bin/python #-*- coding:utf-8 -*- #Author: Ben while True: try: N = input() ways = [0]*41 ways[0] = 1 for i in range(N): weight = input() num = 40 - weight while num >= 0: if ways[num]: ways[num+weight] += ways[num] num -= 1 print ways[40] except: break
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int dp[21][41]; //dp[i][j]表示当有i个物品时,凑成体积为j的方法数
int v[21]; //体积
int main(){
int n;
while(cin>>n){
for(int i=1; i<=n; i++){
cin>>v[i];
}
memset(dp, 0, sizeof(dp));
for(int i=0; i<=n; i++){
dp[i][0] = 1; //当目标体积为0时,只有1种方法就是全不拿
}
for(int i=1; i<=n; i++){
for(int j=1; j<=40; j++){
if(j>=v[i]){//目标体积大于当前物品体积
dp[i][j] = dp[i-1][j] + dp[i-1][j-v[i]];//不拿+拿的方法数
}
else{
dp[i][j] = dp[i-1][j];//只能选择不拿
}
}
}
cout<<dp[n][40]<<endl;
}
return 0;
} #include <bits/stdc++.h>
/*
深度搜索,我们如果找到一个解,那么直接种类加一,返回
*/
using namespace std;
const int MAXN = 25;
const int total = 40; // 总重量
bool visit[MAXN]; // 标记数组
int matter[MAXN]; // 存放物品
int kind = 0; // 记录一共有多少种
int n; // 物品的数量
void DFS(int sum,int position) { // sum为当前已经凑的质量
if(sum==total) {
kind++; // 种数增加
return;
}
// 从第一件开始凑数
for(int i=position; i<n; i++) {
if(visit[i] || sum+matter[i]>total) {
continue;
}
visit[i] = true;
DFS(sum+matter[i],i);
visit[i] = false; // 回溯
}
}
int main() {
cin>>n;
int sum = 0; // 记录所有物品的质量总和
for(int i=0; i<n; i++) {
cin>>matter[i];
sum+=matter[i];
}
sort(matter,matter+n);
// 总和小于40或者最大的已经大于40了
if(sum<40 || matter[0]>40) {
cout<<kind<<endl;
return 0;
} else {
memset(visit,false,sizeof(visit));
DFS(0,0);
cout<<kind<<endl;
}
return 0;
} #include <iostream>#include <cstring>#include <cstdio>using namespace std;#define N 100inta[N],n;int ways(int n,int w){if(w==0) return 1;if(n<=0) return 0;return ways(n-1,w)+ways(n-1,w-a[n]);}int main(){cin>>n;for(inti=1;i<=n;i++)cin>>a[i];cout<<ways(n,40)<<endl;return0;}
import java.util.Scanner;
public class Main1 {
static int count=0;//表示有多少种
static int[] arr; //表示口袋
static int n;//表示物品的种类
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
while(input.hasNext()){
n=input.nextInt();
arr=new int[n+1];
/*这里的大小我们设置的比物品的种类要大1,因为在下边进行递归的时候,
如果大小为n,因为在放第一个的时候还要考虑第一个的前一个(倒着放的:相对正着放方便一点),
数组大小为n的话会造成数组溢出
*/
for(int i=1;i<=n;i++){
arr[i]=input.nextInt();
}
}
count(40,n);
System.out.println(count);
}
public static void count(int s,int n){
/**
* s表示背包剩下的容量大小
* n表示剩下的东西数量
*/
//如果背包容量刚好等于零,说明刚好装满
if(s==0){
count++;
}
//背包容量小于零或者容量大于零但是东西数量小于零,则不能刚好装满(也就是要么装不下了要么不够装了)
if(s<=0||(s>0&&n<0)){
return ;
}
//从最后一个开始装
count(s-arr[n],n-1);
//如果最后一个和其他是都值完了,从倒数第二个开始
count(s,n-1);
}
}
————————————————
版权声明:本文为CSDN博主「峰回路转」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44840148/article/details/104704883 def dfs(arr,vol):
global res
if vol<0:
return
if vol==0:
res+=1
return
for i,v in enumerate(arr):
dfs(arr[i+1:],vol-v)
while True:
try:
a, arr = int(input()), []
for i in range(a):
arr.append(int(input()))
res=0
dfs(arr,40)
print(res)
except:
break
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 21;
int v[maxn]; // 存储每个物品体积
int bite[maxn]; // 用于标记这个物品是否出现在最后的队列中
int count = 0; // 计数器
int total = 0; // 物品总数量
/**
num : 现在要放第几个物品, num >= 0
n : 剩余容积
*/
void solve(int num, int n)
{
if(n == 0)
{
// 没有剩余容积则是一种方法
++count;
return ;
}
if(num == total)
{
// 放到最后也没有结束
return ;
}
bite[num] = 1;
solve(num+1, n-v[num]);
bite[num] = 0;
solve(num+1, n);
}
int main()
{
cin >> total;
for(int i = 0; i < total; ++i)
{
cin >> v[i];
}
solve(0, 40);
cout << count ;
return 0;
}