百练 2755 神奇的口袋

描述
有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an。John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品。现在的问题是,John有多少种不同的选择物品的方式。
输入
输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目。接下来的n行,每行有一个1到40之间的正整数,分别给出a1,a2……an的值。
输出
输出不同的选择物品的方式的数目。
样例输入
3
20
20
20
样例输出
3

枚举,最大2^20.

递归:

#include <iostream>
using namespace std;
int a[30]; int N;
int Ways(int w ,int k ) { // 从前k种物品中选择一些,凑成体积w的做法数目
if( w == 0 ) return 1;
if( k <= 0 ) return 0;
return Ways(w, k -1 ) + Ways(w - a[k], k -1 );
}
int main() {
cin >> N;
for( int i = 1;i <= N; ++ i )
cin >> a[i];
cout << Ways(40,N);
return 0;
}

二维动归:

#include <iostream>
using namespace std;
int a[30]; int N;
int Ways[40][30];//Ways[i][j]表示从前j种物品里凑出体积i的方法数
int main() {
cin >> N;
memset(Ways,0,sizeof(Ways));
for( int i = 1;i <= N; ++ i ) {
cin >> a[i];  Ways[0][i] = 1;
}
Ways[0][0] = 1;
for( int w = 1 ; w <= 40; ++ w ) {
for( int k = 1; k <= N; ++ k ) {
Ways[w][k] = Ways[w][k-1];
if( w-a[k] >= 0) Ways[w][k] += Ways[w-a[k]][k-1];
}
}
cout << Ways[40][N]; return 0;
}

此问题仅在询问容积40是否可达,40是个很小的

数,可以考虑对值域空间-即对容积的可达性进行动态

规划。

定义一维数组 int sum[41];

依次放入物品,计算每次放入物品可达的容积,

并在相应空间设置记录,最后判断sum[40] 是否可达

,到达了几次。

优化:

#include <iostream>
using namespace std;
#define MAX 41
int main(){
int n,i,j,input; int sum[MAX];
for(i=0;i<MAX;i++) sum[i]=0;
cin >> n;
for(i=0;i<n;i++){
cin >> input;
for(j=40;j>=1;j--)
if(sum[j]>0 && j+input <= 40)
sum[j+input] += sum[j];
//如果j有sum[j]种方式可达,则每种方式加上input就可达 j + input
sum[input]++;
}
cout << sum[40] << endl;
return 0;
}

对于sum[j+input] += sum[j];实际指对于所有满足sum[j]>0 && j+input <= 40在原有的sum[j+input]基础上增加sum[j],不断累积n次。另外,sum[input]++的原因是什么呢???

很容易想到sum[input]++就是存储input下标位置的值,那么为什么不能直接也和其他数一样通过sum[input] += sum[0];来得到呢,当我们把j最小设为0不是可以么?也许会有人觉得是这样,但请回头看清题意,物品的体积范围是1-40,也就是说sum[0]恒为0不会发生改变,倘若不特殊处理,那么每次input下标所对应的位置都将少1.

时间: 2024-08-08 05:37:39

百练 2755 神奇的口袋的相关文章

百练2755 神奇的口袋 【深搜】or【动规】or【普通递归】or【递推】

总Time Limit:  10000ms  Memory Limit:  65536kB 有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40.John现在有n个想要得到的物品,每个物品的体积分别是a1,a2--an.John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品.现在的问题是,John有多少种不同的选择物品的方式. Input 输入的第一行是正整数n (1 <= n <= 20),表示不

OpenJudge Bailian 2755 神奇的口袋 DP

神奇的口袋 Time Limit:10000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Bailian 2755 Description 有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40.John现在有n个想要得到的物品,每个物品的体积分别是a 1,a 2……a n.John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物

OpenJudge 2755:神奇的口袋

总时间限制: 10000ms 内存限制: 65536kB 描述 有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40.John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an.John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品.现在的问题是,John有多少种不同的选择物品的方式. 输入 输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目.接下来的n行,每行

[OpenJudge] 百练2754 八皇后

八皇后 Description 会下国际象棋的人都很清楚:皇后可以在横.竖.斜线上不限步数地吃掉其他棋子.如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题. 对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2...b8,其中bi为相应摆法中第i行皇后所处的列数.已经知道8皇后问题一共有92组解(即92个不同的皇后串).给出一个数b,要求输出第b个串.串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小. I

poj 百练 2765 八进制小数(精度问题)

2765:八进制小数 查看 提交 统计 提示 提问 总时间限制:  1000ms  内存限制:  65536kB 描述 八进制小数可以用十进制小数精确的表示.比如,八进制里面的0.75等于十进制里面的0.963125 (7/8 + 5/64).所有小数点后位数为n的八进制小数都可以表示成小数点后位数不多于3n的十进制小数. 你的任务是写一个程序,把(0, 1)中的八进制小数转化成十进制小数. 输入 输入包括若干八进制小数,每个小数占用一行.每个小数的形式是0.d1d2d3 ... dk,这里di

BZOJ 1416: [NOI2006]神奇的口袋( 高精度 )

把x1~xn当成是1~n, 答案是不会变的. 然后直接模拟就行了...... P.S 双倍经验... BZOJ1416 && BZOJ1498 ------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; c

ACM/ICPC 之 递归(POJ2663-完全覆盖+POJ1057(百练2775)-旧式文件结构图)

POJ2663-完全覆盖 题解见首注释 //简单递推-三个米诺牌(3*2)为一个单位打草稿得出规律 //题意-3*n块方格能被1*2的米诺牌以多少种情况完全覆盖 //Memory 132K Time: 0 Ms #include<iostream> #include<cstring> #include<cstdio> using namespace std; int ans; //开始平铺 int Tiling(int n) { int sum = 0; if (n =

百练8216-分段函数-2016正式A题

百练 / 2016计算机学科夏令营上机考试 已经结束 题目 排名 状态 统计 提问 A:分段函数 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 编写程序,计算下列分段函数y=f(x)的值. y=-x+2.5; 0 <= x < 5 y=2-1.5(x-3)(x-3); 5 <= x < 10 y=x/2-1.5; 10 <= x < 20 输入 一个浮点数N,0 <= N < 20 输出 输出N对应的分段函数值:f

百练 1088 滑雪

“人人为我”的解法: dp[i][j]表示坐标为(i,j)的点开始下滑的最大长度. 则dp[i][j]为(i,j)周围四个点中比(i,j)低,且最大长度最大再加一的值 用结构体来储存一个点的坐标和高度,这样按高度从小到大排完序以后还不会丢失坐标的值 从小到大遍历所有的点,经过一个点(i,j)时,用递推公式求L(i,j). 一个小技巧: 将矩阵height四周的值赋值为INF,你可以想想这是滑雪场四周非常非常高的围墙. 这样就避免了数组越界的判断,而且不会影响正确结果(因为我们找的是滑雪场内部的最