E - Operations

Analysis

Let’s revisit the Knapsack problem first.

Knapsack Problem

Given \(n\) types of items, item of type \(i\) has weight \(w_i\) and value \(v_i\). You have a bag with capacity \(C\). You have to choose the items such that the sum of items chosen is at most \(C\) and the sum of values should be maximised.

  • [Unbounded Version] There are infinite numbers of items of each type
  • [0-1 Version] Each type of item can only be chosen at most once.

Codes

  • #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    /**
     * Solves the problem of finding the maximum achievable score.
     *
     * @param T The target score
     * @param A First increment value
     * @param B Second increment value
     * @return The maximum achievable score
     */
    int solve(int T, int A, int B) {
      bool *f = calloc(T + 1, sizeof(bool));
      f[0] = true;
    
      for (int i = 0; i <= T; ++i) {
        if (f[i]) {
          if (i + A <= T) {
            f[i + A] = true;
          }
          if (i + B <= T) {
            f[i + B] = true;
          }
        }
      }
    
      for (int i = 0; i <= T; ++i) {
        if (f[i]) {
          f[i / 2] = true;
        }
      }
    
      for (int i = 0; i <= T; ++i) {
        if (f[i]) {
          if (i + A <= T) {
            f[i + A] = true;
          }
          if (i + B <= T) {
            f[i + B] = true;
          }
        }
      }
    
      for (int i = T; i >= 0; --i) {
        if (f[i]) {
          free(f);
          return i;
        }
      }
    
      free(f);
      return 0;
    }
    
    int main() {
      int T, A, B;
      scanf("%d %d %d", &T, &A, &B);
      printf("%d\n", solve(T, A, B));
      return 0;
    }
    
  • #include <algorithm>
    #include <iostream>
    #include <vector>
    
    class Solution {
     public:
      /**
       * @param n: the number of positions
       * @param k: the number of chosen positions
       * @param x: vector of positions
       * @return: return the maximum minimum distance between any two chosen
       * positions
       */
      static int solve(int T, int A, int B) {
        std::vector<bool> dp(T + 1);
        dp[0] = true;
        for (int i = 0; i <= T; ++i) {
          if (dp[i]) {
            if (i + A <= T) dp[i + A] = true;
            if (i + B <= T) dp[i + B] = true;
          }
        }
        for (int i = 0; i <= T; ++i)
          if (dp[i]) dp[i >> 1] = true;
        for (int i = 0; i <= T; ++i) {
          if (dp[i]) {
            if (i + A <= T) dp[i + A] = true;
            if (i + B <= T) dp[i + B] = true;
          }
        }
        for (int i = T; i; --i) {
          if (dp[i]) return i;
        }
      }
    };
    
    int main() {
      int T, A, B;
      std::cin >> T >> A >> B;
      std::cout << Solution::solve(T, A, B) << std::endl;
      return 0;
    }
    
  • import java.util.Arrays;
    import java.util.Scanner;
    
    public class Solution {
      /**
       * @param t: The limit of the total capacity
       * @param a: The first increment value
       * @param b: The second increment value
       * @return: return the maximum achievable score
       */
      public static int solve(int t, int a, int b) {
        boolean dp1[] = new boolean[t + 1];
        Arrays.fill(dp1, false);
    
        dp1[0] = true;
        for (int i = 0; i < t; i++) {
          if (dp1[i]) {
            if (i + a <= t)
              dp1[i + a] = true;
            if (i + b <= t)
              dp1[i + b] = true;
          }
        }
    
        boolean dp2[] = new boolean[t + 1];
        Arrays.fill(dp2, false);
        for (int i = 0; i <= t; i++) {
          if (dp1[i])
            dp2[i / 2] = true;
        }
    
        for (int i = 0; i < t; i++) {
          if (dp2[i]) {
            if (i + a <= t)
              dp2[i + a] = true;
            if (i + b <= t)
              dp2[i + b] = true;
          }
        }
    
        for (int i = t; i >= 0; i--) {
          if (dp1[i] || dp2[i])
            return i;
        }
    
        return 0;
      }
    
      public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
    
        int t = input.nextInt();
        int a = input.nextInt();
        int b = input.nextInt();
    
        System.out.println(solve(t, a, b));
        input.close();
      }
    }
    
  • class Solution:
        @staticmethod
        def solve(t: int, a: int, b: int) -> int:
            """
            Solves the problem of finding the maximum achievable score.
    
            Args:
                t (int): The limit of the total capacity
                a (int): The first increment value
                b (int): The second increment value
    
            Returns:
                int: The maximum achievable score
            """
            f = [False] * (t + 1)
            f[0] = True
    
            for i in range(t + 1):
                if f[i]:
                    if i + a <= t:
                        f[i + a] = True
                    if i + b <= t:
                        f[i + b] = True
    
            for i in range(t + 1):
                if f[i]:
                    f[i // 2] = True
    
            for i in range(t + 1):
                if f[i]:
                    if i + a <= t:
                        f[i + a] = True
                    if i + b <= t:
                        f[i + b] = True
    
            for i in range(t, -1, -1):
                if f[i]:
                    return i
    
            return 0
    
    
    if __name__ == "__main__":
        t, a, b = map(int, input().split())
        print(Solution.solve(t, a, b))