WalzoneInterview Prep
📞 Interviewing soon? Practice with a realistic AI mock phone interview — it calls you, then scores you. First 15 min FREE →

Dynamic Programming · Guru · question 93 of 100

Implement the solution to the Resource Allocation with Time Windows and Precedence Constraints problem using dynamic programming.?

📕 Buy this interview preparation book: 100 Dynamic Programming questions & answers — PDF + EPUB for $5

The Resource Allocation with Time Windows and Precedence Constraints problem is a classic optimization problem, where we are given a set of tasks to be executed, with each task having a start time, end time, required resources and a set of other tasks that have to be finished before it can start. The goal of the problem is to minimize the total cost of executing all tasks, subject to the constraints.

To solve this problem using dynamic programming, we need to define a set of subproblems and their optimal solutions. Let’s define the subproblem as follows:

Subproblem: Given a set of tasks T, where each task has an assigned start and end time, and a set of resource assignments for each time interval, find the minimum cost of executing the subset of tasks from T that are compatible with the resource assignments.

Here, "compatible with the resource assignments" means that each task can be executed during its respective time interval, and that there are enough resources available during that interval to execute the task.

To solve this subproblem, we can use the following recursive formula:

dp[t][S] = min { dp[t-1][S'] + cost[t][S-S'] }

where dp[t][S] is the minimum cost of executing the subset of tasks in T[1...t] that are compatible with the resource assignments S, cost[t][S-S’] is the cost of executing the task t using the resources in S-S’, and S’ is the set of resource assignments that are compatible with task t.

To compute dp[t][S], we need to iterate over all possible subsets of S’ that are compatible with task t. This can be done by iterating over all possible bitmasks (i.e., integers in the range [0, 2R − 1], where R is the number of resources) and checking if the set bits in the bitmask correspond to a valid resource assignment.

The base case of the recursion is dp[0][S] = 0, since there are no tasks to execute.

After computing dp[T][S] for all possible subsets S of the resource assignments, the optimal solution to the original problem is the minimum value of dp[T][S] over all possible subsets S.

Here’s a possible implementation of the algorithm in Java:

public int resourceAllocation(int[][] tasks, int[][] precedences, int[] resources) {
    int n = tasks.length;
    int R = resources.length;

    // create a binary matrix to represent precedences
    boolean[][] prec = new boolean[n][n];
    for (int[] p : precedences) {
        prec[p[1]][p[0]] = true;
    }

    // initialize the dp table
    int[][] dp = new int[n+1][1<<R];
    for (int t = 1; t <= n; t++) {
        Arrays.fill(dp[t], Integer.MAX_VALUE);
    }

    // base case: no tasks to execute
    Arrays.fill(dp[0], 0);

    // compute the dp table
    for (int t = 1; t <= n; t++) {
        for (int S = 0; S < (1<<R); S++) {
            // iterate over all possible subsets of S' that are compatible with task t
            for (int S1 = S; ; S1 = (S1-1) & S) {
                if (compatible(tasks[t-1], S-S1)) {
                    int cost = computeCost(tasks[t-1], S-S1);
                    dp[t][S] = Math.min(dp[t][S], dp[t-1][S-S1] + cost);
                }
                if (S1 == 0) break;
            }
        }
    }

    // find the minimum cost over all possible subsets of the resource assignments
    int minCost = Integer.MAX_VALUE;
    for (int S = 0; S < (1<<R); S++) {
        if (compatible(tasks[n-1], S)) {
            boolean feasible = true;
            for (int t = n-1; t >= 0; t--) {
                if (!compatible(tasks[t], S)) {
                    feasible = false;
                    break;
                }
                for (int j = 0; j < n; j++) {
                    if (prec[t][j] && ((S & (1<<j)) == 0)) {
                        feasible = false;
                        break;
                    }
                }
                if (!feasible) break;
            }
            if (feasible) {
                minCost = Math.min(minCost, dp[n][S]);
            }
        }
    }
    return minCost;
}

// check if task t is compatible with the resources in S
private boolean compatible(int[] task, int S) {
    for (int j = 0; j < task.length-2; j++) {
        if (((S>>j) & 1) == 1 && task[j+2] == 0) {
            return false;
        }
    }
    return true;
}

// compute the cost of executing task t using the resources in S
private int computeCost(int[] task, int S) {
    int cost = 0;
    for (int j = 0; j < task.length-2; j++) {
        if (((S>>j) & 1) == 1) {
            cost += task[j+2];
        }
    }
    return cost;
}

In this implementation, the ‘tasks‘ array contains the start time, end time, and resource requirements for each task, the ‘precedences‘ array contains the precedence constraints, and the ‘resources‘ array contains the capacity of each resource.

The algorithm first converts the ‘precedences‘ array into a binary matrix ‘prec‘, where ‘prec[i][j]‘ is true if task ‘i‘ has to be finished before task ‘j‘ can start.

Then, the dp table is initialized with infinite cost, except for dp[0][S] = 0, which corresponds to the base case.

The algorithm then iterates over all tasks and all possible subsets of the resource assignments, and computes the optimal solution using the recursive formula described above.

Finally, the algorithm finds the minimum cost over all possible subsets of the resource assignments that satisfy the precedence constraints and are compatible with the resource requirements of the last task.

Note that this implementation is not optimized for space, since it uses a 2D table ‘dp‘ of size (n + 1)x2R. However, it should be possible to optimize the space complexity to O(2R) by using rolling arrays.

Reading is step one. Saying it out loud is the interview. Our AI interviewer calls your phone and runs a realistic Dynamic Programming interview — then scores it.
📞 Practice Dynamic Programming — free 15 min
📕 Buy this interview preparation book: 100 Dynamic Programming questions & answers — PDF + EPUB for $5

All 100 Dynamic Programming questions · All topics