百练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),表示不同的物品的数目。接下来的n行,每行有一个1到40之间的正整数,分别给出a1,a2……an的值。
Output
输出不同的选择物品的方式的数目。
Sample Input
3
20
20
20
Sample Output
3

这题很经典,可以用很多方法来做,我试了以下几种:

DFS:耗时0ms

#include <stdio.h>

int arr[22], ans, n, sum;

void DFS(int k)
{
    if(sum >= 40){
        if(sum == 40) ++ans;
        return;
    }
    for(int i = k; i <= n; ++i){
        sum += arr[i];
        DFS(i + 1);
        sum -= arr[i];
    }
}

int main()
{
    int i;
    scanf("%d", &n);
    for(i = 1; i <= n; ++i)
        scanf("%d", arr + i);
    sum = ans = 0; DFS(1);
    printf("%d\n", ans);
    return 0;
}

普通递归:耗时60ms

#include <stdio.h>

int arr[22], n;

int getAns(int sum, int k)
{
    if(sum == 0) return 1;
    if(k == 0) return 0;
    return getAns(sum, k - 1) + getAns(sum - arr[k], k - 1);
}

int main()
{
    int i;
    scanf("%d", &n);
    for(i = 1; i <= n; ++i)
        scanf("%d", arr + i);
    printf("%d\n", getAns(40, n));
    return 0;
}

DP:耗时0ms

#include <stdio.h>

int arr[22], n, dp[42][22];
//dp[i][j]表示从前j种物品里配出价值i的方法数
int main()
{
    int i, j;
    scanf("%d", &n);
    for(i = 1; i <= n; ++i){
        scanf("%d", arr + i);
        dp[0][i] = 1;
    }
    for(dp[0][0] = i = 1; i <= 40; ++i){
        for(j = 1; j <= n; ++j){
            dp[i][j] = dp[i][j - 1];
            if(i - arr[j] >= 0) dp[i][j] += dp[i - arr[j]][j - 1];
        }
    }
    printf("%d\n", dp[40][n]);
    return 0;
}

递推型DP:耗时0ms

#include <stdio.h>

int n, sum[42];
//sum[i]表示价值能组成i的方法数
int main()
{
    int i, j, temp;
    scanf("%d", &n);
    for(i = 0, sum[0] = 1; i < n; ++i){
        scanf("%d", &temp);
        for(j = 40; j; --j){
            if(j + temp > 40) continue;
            if(sum[j]) sum[j + temp] += sum[j];
        }
        ++sum[temp];
    }
    printf("%d\n", sum[40]);
    return 0;
}
时间: 2025-01-31 00:31:33

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

百练 2755 神奇的口袋

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

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行,每行

NYOJ 10 skiing (深搜和动归)

skiing 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描写叙述 Michael喜欢滑雪百这并不奇怪. 由于滑雪的确非常刺激.但是为了获得速度.滑的区域必须向下倾斜.并且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道载一个区域中最长底滑坡.区域由一个二维数组给出.数组的每一个数字代表点的高度.以下是一个样例 1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9

深搜基础题目 杭电 HDU 1241

HDU 1241 是深搜算法的入门题目,递归实现. 原题目传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1241 代码仅供参考,c++实现: #include <iostream> using namespace std; char land[150][150]; int p,q; void dfs(int x,int y){ land[x][y] = '*'; if(land[x-1][y]!= '@' && land[x+1]

DFS-BFS(深搜广搜)原理及C++代码实现

深搜和广搜是图很多算法的基础,很多图的算法都是从这两个算法中启发而来. 深搜简单地说就是直接一搜到底,然后再回溯,再一搜到底,一直如此循环到没有新的结点. 广搜简单地说就是一层一层的搜,像水的波纹一样往外面扩散,扩散到最外层搜索也就完成了. prim最小生成树.Dijkstra单源最短路径算法都使用了类似广度优先搜索的思想. 拓扑排序就可以用深搜来实现,分解强连通分量也可以用深搜来实现(转置图加两次深搜) 我们实现广搜时需要用队列来辅助我们进行.实现深搜时使用栈来辅助我们进行,所以显而易见的用递

深搜--P1036选数

深搜中绝对会用到递归 因此本题也可以使用深搜来做 bool prime(int b) { memset(sz, true, sizeof(sz)); sz[1]=false; for (int i=2;i<=b;i++) { if (sz[i]) { for (int j=2*i;j<=b;j+=i) sz[j]=false; 定义一个dfs函数来解决对数的搜索 step代表执行步数 sum代表已经选好的数据的和 cet代表已经选完的数的个数 接下来进行搜索 另外介绍下非朴素版的寻找质数的方法

fzu 1920 Left Mouse Button(简单深搜题)

题目地址:http://acm.fzu.edu.cn/problem.php?pid=1920 题目大意是给定一个n*n的图,模拟扫雷游戏,0代表没有雷区,1代表附近九宫格内只有一个雷-- 如果不懂的话去玩下扫雷,挺好玩的,99个雷的玩了好几百盘才赢了一次............ 此题假设神操作,点不到雷,问你最少要多少下才可以把图中非雷的点完,怎么样才最快呢? 当然先点0啦,,,,,,,, 好吧,不废话了..... ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1

嵌套矩形 DAG上的dp(深搜+dp)

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=16 矩形嵌套 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度).例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中.你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一