Algorithm learning - 0-1 knapsack of knapsack problem

I was frustrated recently when I was trying to make a profit plan for the Likou Backpack topic. . . And this question also triggered my thinking about one of the knapsack problems. At present, the number of solutions for the knapsack problem on Likou is exactly selected, and there is no such thing as the most selected. For example, if you buckle up the title, the sum of the goals is the number of all the plans that reach a certain value. And when I was doing the question of profit plan, I thought about it, so I thought and created a question by myself, you can also try to do it yourself~~~

Give you an array nums, and then give you an int number n, ask to take any number of numbers from the array, but each number can only be taken once, if the sum of the taken numbers is less than the given n, it is a solution. What is the number of all the plans? For example, nums=[1,2,3] n=6, then all the schemes are { {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}} 7 kinds. If n=5, the number of schemes is 6.

You can also think about it and do it yourself. Post my own ideas and code here.

This is also a typical 0-1 knapsack problem. First of all, dynamic programming is used here. First, a two-dimensional array dp[i,j] is defined. This array represents the selection of the i-th element in the array, and the limit value is j. total number of programs. There are two situations here, the first one, when nums[i-1]>limit, it means that this number cannot be put in, so the number of plans should be the same as dp[i-1, limit] and we can With the first equation: 

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

The second case: When nums[i-1]<=limit, it means that this number can be added to the number of schemes. Here, the default dp[i,j]=1; this is a scheme that only puts in itself number, the equation is:

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

The meaning of this equation is that the number of solutions limited to j in this round plus the number of solutions limited to j in the previous round plus the number of solutions limited to j-nums[i-1] in the previous round, because this The nums[i-1] of the round can be put in, so it contains the number of plans that are not put in, that is, dp[i-1,j], and the number of plans after putting in, put After entering, because it cannot exceed the maximum limit j value, that is, dp[i-1,j-nums[i-1]]; (When i is fixed, the number of rounds with larger j must include the part with smaller j ).

Paste my code here:

        /// <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];
         }

At this point we can see that there is still room for optimization in the code. We can reduce the space by one dimension and use rolling arrays. But the general idea remains the same and I will post the code below.

 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];
        }

Guess you like

Origin blog.csdn.net/X1iaoXu666/article/details/124624283