2
votes

I'm working on an old contest problem from 2019 from this page: https://dmoj.ca/problem/ccc19s4

You are planning a trip to visit N tourist attractions. The attractions are numbered from 1 to N and must be visited in this order. You can visit at most K attractions per day, and want to plan the trip to take the fewest number of days as possible.

Under these constraints, you want to find a schedule that has a nice balance between the attractions visited each day. To be precise, we assign a score ai to attraction i. Given a schedule, each day is given a score equal to the maximum score of all attractions visited that day. Finally, the scores of each day are summed to give the total score of the schedule. What is the maximum possible total score of the schedule, using the fewest days possible?

Apparently it's a dynamic programming type of problem, which I can see how, but I can't seem to figure out how to break it down to subproblems and how each subproblem would relate to each other, especially when there are two variables N and K.

I threw together a recursive brute-force algorithm which works for smaller inputs but fails when the inputs get too large:

int daysNeeded = (int) Math.ceil((double) N / K);

// n - index of current attraction being visited
// d - days used up
public static long solve(int n, int d) {
    if (d == daysNeeded) { // Base case, stop once we reach the min days required
        if (n == N) // If we visited all attractions, count this answer
            return 0;
        else // If we didn't visit all attractions, don't count this answer
            return Integer.MIN_VALUE;
    }
    
    long result = 0;
    
    // Try to visit attractions up to K
    //
    // i + 1 is the number of attractions to visit in this day
    for (int i = 0; i < K; i++) {
        if (n + i >= N)
            break;
        
        long highestScore = attractions[n];

        // Find the attraction from [n + j ... n + i] with the highest score
        for (int j = 1; j <= i; j++) {
            highestScore = Math.max(highestScore, attractions[n + j]);
        }
        
        long next = highestScore + solve(n + i + 1, d + 1);
        
        // Find the attraction with the highest score out of all attractions from 0 to i
        result = Math.max(result, next);
    }
    
    return result;
}

How would you find an optimized algorithm using DP? I can't seem to find any solutions or hints online for this specific problem.

2
If you cache solve(n, d) you have a dynamic programming solution.Paul Hankin
I didn't get what's the point of that "daysNeeded" (N divided by K) ?mangusta
this looks like an optimization problem but it has two objective functions and unclear which one is given a priority - the max score or the min number of days? your solution assumes that the number of days could be at most N/K (similar to knapsack capacity) but I can't see anything about that constraint in the problem statementmangusta
ah, moreover you assume that the number of days should EXACTLY be N/K but there could be a better score with more number of days. anyway the problem statement is ambiguous and needs to be revisedmangusta
@mangusta if we can have any number of days, the maximum achievable score would be to simply visit one attraction per day. The number of days isn't at most ceil(n/k), it's exactly ceil(n/k). Any fewer days would achieve a lower score.גלעד ברקן

2 Answers

0
votes

I will try to give the solution as a recurrence relation. Let m be the number of days to visit all attractions and let P[m][N] be the optimal value you obtain by visiting N attractions in m days. We don't know P yet but we will reason about it.

P[m][N]=max_{i up to k} ( P[m-1][N-i]+max_{l=0 to i-1}(a[l]) )

For example if you get the optimal score by visiting only the last two attractions on the last day then the score for that day is max(a[N],a[N-1]) and the total (optimal) score will be

P[m][N]=max(a[N],a[N-1])+optimal score to visit N-2 attractions in m-1 days

which is exactly the same as the above formula

P[m][N]=max(a[N],a[N-1]+ P[m-1][N-2]

Note that there is a constraint on i> N/k(m-1) because if you don't visit enough attractions on the last day the remaining days might not be enough to visit the rest.

0
votes

Lets start out by assigning K attractions to each day, except for the last, which will be length M = N mod K. For example:

5 3
2 5 7 1 4

2 5 7|1 4  (M = 5 mod 3 = 2)

Observe that we cannot extend any of the K length days, neither can we shrink any of them, unless we first extend the smaller, M length, day. Note that the maximum amount we can extend is equal to K - M = K - (N mod K).

Now let dp[d][m] represent the the optimal score for days 1...d when day d+1 has extended m attractions into our starting dth day. Call the number of days needed D = ceil(N / K). Then:

dp[1][m] = max(attractions[0..k-m-1])

dp[D][m] = max(attractions[i-m..j]) + dp[D-1][m]

dp[d][m] = max(attractions[i-l..j-m]) + dp[d-1][l]

  where (i, j) mark the starting dth day
  and 0 ≤ l ≤ m

and the answer will be the best of dp[D][m].

We can fold into the routine our calculation of the relevant maximum in O(1): preprocess prefix maximums from left to right for each of our starting sections (meaning days) in O(n). For each loop of max(attractions[i-l..j-m]), start with the max provided at j-m in the prefix maximum, then update the maximum by comparing the current one with each attractions[i-l], as l is incremented.

Overall complexity would seem to be O(ceil(N / K) * (K - (N mod K))^2).

We can do better, time-wise, by observing that as m is incremented, we may be able to skip the iteration on l if the starting max didn't change or a max that was greater than the starting max was chosen before (meaning it came from left of i). In those cases, we only need to consider the new l, which is one greater than we checked before. We can rely on a right-to-left prefix max combined with our left-to-right prefix max to get this new max in O(1).

In the case of our simple example, we have:

2 5 7 1 4

dp[1][0] = max(2, 5, 7) = 7
dp[1][1] = max(2, 5) = 5

dp[2][0] = max(1, 4) + dp[1][0] = 11
dp[2][1] = max(7, 1, 4) + dp[1][1] = 12