简体   繁体   中英

How would you break this problem into subproblems and use dynamic programming?

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 a i 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.

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][Ni]+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.

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 d th 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[il..jm]) , start with the max provided at jm in the prefix maximum, then update the maximum by comparing the current one with each attractions[il] , 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM