zoukankan      html  css  js  c++  java
  • 神奇的口袋(百练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

    思路:思路有两种,一种是递归的方法;另一种是动态规划dp。

    ①对于递归方法:对于挑选某个物品,都有2种选择:选择当前物品后再取看下一个物品或者是不选当前这个物品直接去看下一个物品,故方法数为这两种情况和。此处的递归是从后向前进行的(先访问j再去访问j-1)。因此对于第j个物品,它的体积为v[j],如果不挑选的话则容量剩为i,因此在前j个物品中,不挑选j物品而总体积达到i的方法总数为way(i,j-1);如果挑选的话则容量剩为i-v[j],因此此时在前j个物品中,挑选j物品总体积达到i的方法总数为way(i-v[j],j-1)。因此在前j个物品中,让物品总体积达到i的方法总数为way(i,j)=way(i,j-1)+way(i-v[j],j-1)。

    关键要点:从多个重复的状态中单独取出一个状态进行分析,分析当前状态与下一个状态的联系,从而推广到全局。

    ②对于动态规划:思路和法①基本接近。只不过一个是递归实现,一个是循环递推实现,可以根据①来设计主要的核心算法:

    伪语言描述:

    if 当前剩余容积i<第j个物品大小v[j]
        dp[i][j] = dp[i][j-1];//不放第j个物品的放法,容积不够只能不选
    else if  当前剩余容积i>=第j个物品大小v[j]    //容积足够
        dp[i][j] =dp[i][j-1]+dp[i - v[j]][j - 1];    //对第j个物品选择和不选择两种做法  方法数加和

    递归实现代码:

    #include<stdio.h>
    #include<string.h>
    int a[30]; 
    int Way(int x,int n)
    {
        if(x==0)
            return 1;
        if(n<=0)
            return 0;
        return Way(x,n-1)+Way(x-a[n],n-1);//可以选择选这个物品和不选这个物品 
    }
    int main()
    {
        int i,j,n,m;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
        printf("%d
    ",Way(40,n));
        return 0;
    }
    
    //时间复杂度O(2^N)

    dp实现代码:

    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    using namespace std;
    
    int main()
    {
        int n;
        int v[50];
        int dp[50][50];//dp[i][j]表示从前j个物品中凑出体积为i的做法有多少种(即挑完j个抵达体积i的方法数)
        cin >> n;
        for (int i = 1; i <= n; ++i)
        {
            cin >> v[i];
        }
        memset(dp, 0, sizeof(dp));
        //边界条件:有物品,凑出体积为0的做法为1(一个物品都不放)
        for (int i = 0; i <= n; ++i)
        {
            dp[0][i] = 1;
        }
        for(int i = 1;i<=40;++i)
            for (int j = 0; j <= n; ++j)
            {
                dp[i][j] = dp[i][j-1];//不放第j个物品的放法
                if (i >= v[j])
                {
                    dp[i][j] += dp[i - v[j]][j - 1];
                }
            }
        cout << dp[40][n] << endl;
        return 0;
    }
  • 相关阅读:
    MySQL 5.1.73升级为MySQL 5.5.35详解
    MySQL 常用show命令
    MySQL 用户与授权管理详解
    MySQL 日志管理详解
    MySQL 5.5.35 单机多实例配置详解
    mysql启动与关闭(手动与自动)
    hduTHE MATRIX PROBLEM(差分约束)
    在 iPad和 iPhone的浏览器上查看网页源代码
    《30天自制操作系统》之——第3天
    python network programming tutorial
  • 原文地址:https://www.cnblogs.com/xwh-blogs/p/12872871.html
Copyright © 2011-2022 走看看