Knapsacking

The general problem:

Given a list of N items with weights W, amounts A, values V, and a knapsack capacity M, find the maximum value to place in the knapsack.

There are 2 possible algorithms. The easy one is DP on [M][N]; works if M*N < 5 million or so. Otherwise you need a branch and bound algorithm.

The DP is obvious so only the B+B is included here:

import java.util.* ; import java.math.* ; /******************************************************* *                                                     * *                    Lord Klotski                      * *                                                     * ********************************************************/ class zerg implements Comparable&lt;zerg&gt; {    long w, val, amt ; public zerg(long a, long b, long c) {w = a; val = b; amt = c; } public int compareTo(zerg X)    { double t = this.val ; t /= this. w ; double u = X.val ; u /= X.w ; if (t > u)            return -1 ; return 1 ; } } public class Bucharest_I_Robbery {    static long bestMax ; static zerg[] arr ; public static long solve(long capacity, long cur, int t)    { // cutting condition if (cur + (long)LP(capacity) < bestMax) {            return cur ; }        if (t >= arr.length) return cur ; // we add item t        long tempsauce = arr[t].amt ; arr[t].amt = 0 ; long bM = 0 ; for (long i = 0 ; i <= tempsauce ; i ++) {            // branch on item t             if (capacity >= arr[t].w  * i)             { bM = Math.max(bM,solve((capacity-arr[t].w*i),cur + arr[t].val * i,t+1)) ; }        }         arr[t].amt = tempsauce ; if (bM > bestMax) bestMax = bM ; return bM ; }    public static long LP(long capacity) {        // greedy plus partial knapsack long res = 0 ; for (int i = 0 ; i < arr.length ; i ++ ) {            if (arr[i].amt == 0) continue ; double put = Math.min(arr[i].amt,(double)capacity/(double)arr[i].w) ; res += (long)(put * (double)arr[i].val) ; capacity -= put * arr[i].w ; }        return res ; }    public static long greedy(int capacity) {        long res = 0 ; for (int i = 0 ; i < arr.length ; i ++ ) {            if (capacity >= arr[i].w)             { long put = Math.min(arr[i].amt,capacity/arr[i].w) ; res += put * arr[i].val ; capacity -= put * arr[i].w ; }        }         return res ; }    public static void main(String[] args) {        Scanner input = new Scanner(System.in) ; int T = input.nextInt ; while (T --> 0) {            int N, M ; N = input.nextInt ; M = input.nextInt ; arr = new zerg[N] ; int[] t1, t2 ; t1 = new int[N] ; t2 = new int[N] ; for (int i = 0 ; i < N ; i ++) {                t1[i] = input.nextInt ; }            for (int i = 0 ; i < N ; i ++) {                t2[i] = input.nextInt ; }            for (int i = 0 ; i < N ; i ++) {                arr[i] = new zerg((long)t1[i],(long)t2[i],(long)i+1) ; }            Arrays.sort(arr) ; bestMax = greedy(M) ; solve(M,0,0) ; System.out.println(bestMax); }    } } In the solution above, AMT[i] = i. In general:

1) 0-1 knapsack: set AMT to 1

2) Bounded knapsack: Read this number in.

3) Unbounded knapsack: Set this to infinite. Unfortunately, this algorithm needs modification if you want it to work. Unbounded knapsack also has some dominance relations you can use to simplify the search space. This algorithm does not have a running time, but it is quite fast.

Short description:

1) Sort elements in non-increasing order of value/weight

2) Run greedy for a lower bound on the best value

3) At each stage, branch on all possible amounts (0 to amt)

4) The LP-relaxation is partial knapsack; use greedy.

5) Cut any leaves that have an LP-relaxation less than the current best value