算法学习——背包问题之0-1背包

本人最近在刷力扣背包题目盈利计划的时候受挫了。。。而这道题目也引发了我对背包问题其中一种情况的一个思考。目前力扣上的背包题目求方案数都是恰好选到多少什么的,并没有那种最多选到的这种情况。就比如力扣上题目,目标和,就是到达某一个数值的所有方案数。而在我做盈利计划这一道题的时候我就思考到了,所以我自己思考创造了一道题目,大家也可以试着自己做做看~~~

给你一个数组nums,再给你一个int数n,问从数组中取任意数量的数,但是每个数只能取一次,若取出来的数字之和小于给定的n则算一种方案,问所有的方案数为多少?例如 nums=[1,2,3]  n=6     则所有的方案数为{ {1}  ,{2},{3},{1,2},{1,3},{2,3},{1,2,3}}7种。若 n=5 则方案数为6种。

大家也可以自己思考一下,做一下。这里贴出我自己的思路和代码。

这个也是一道典型的0-1背包问题首先这里使用的是动态规划,先定义一个二维数组dp[i,j],这个数组代表选择到数组中第i个元素,限定值为j的时候的方案总数。这里有两种情况,第一种,当nums[i-1]>limit的时候,说明这个数是放不进去的,所以方案数应该和dp[i-1,limit]是一样到达我们就可以有第一个方程: 

dp[i,limit] =dp[i-1,limit];

第二种情况:当nums[i-1]<=limit的时候,说明此数字是可以加入方案数的,这里先默认dp[i,j]=1;这个是仅放入自己的一种方案数,方程为:

dp[i,j]+=dp[i-1,j]+dp[i-1,j-nums[i-1]];

这个方程的含义呢就是,这一轮的限定为j方案数加上上一轮限定为j的方案数再加上上一轮限定为j-nums[i-1]的方案数,因为这一轮的nums[i-1]是可放入的,所以他包含着,不放入的那一种情况的方案数也就是dp[i-1,j],以及放入之后的方案数,放入之后由于不能超过最大限定j值,也就是   dp[i-1,j-nums[i-1]];(当i一定时,j越大那一轮方案数肯定是包含j小的那一部分)。

这里贴一下本人的代码:

        /// <summary>
        /// 有上限的方案数
        /// </summary>
        /// <param name="nums"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        public static int LimitSchemes(int[] nums, int limit)
        {
           int n = nums.Length;
            int[,] dp = new int[n + 1, limit + 1];
            for (int i = 1; i <= n; i++)
            {
                if (nums[i - 1] > limit)
                {
                    dp[i, limit] = dp[i - 1, limit];
                }
                for (int j = nums[i - 1]; j <= limit; j++)
                {
                    dp[i, j] = 1;
                    dp[i, j] += dp[i - 1, j] + dp[i - 1, j - nums[i - 1]];
                }
            }
            return dp[n, limit];
         }

到这里我们可以看到其实代码还有优化的地方,空间我们可以再降低一维,利用滚动数组。但是总体思路不变代码我贴在下面。

 public static int LimitSchemes(int[] nums, int limit)
        {
           
            int n = nums.Length;
            int[] dp = new int[limit + 1];
            for (int i = 0; i < n; i++)
            {
                for (int j = limit; j >= nums[i]; j--)
                {
                    dp[j] += 1 + dp[j - nums[i]];//这里的1就是仅包含自己的那一种方案数
                }
            }
            return dp[limit];
        }

猜你喜欢

转载自blog.csdn.net/X1iaoXu666/article/details/124624283