Open In App

CSES Solutions – Movie Festival II

Last Updated : 01 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In a movie festival, N movies will be shown. Syrjälä’s movie club consists of K members, who will all be attending the festival. Given the starting and ending times of each movie. What is the maximum total number of movies the club members can watch entirely if they act optimally?

Examples:

Input: N = 5, K = 2, movies = {{1, 5}, {8, 10}, {3, 6}, {2, 5}, {6, 9}}
Output: 4
Explanation: The first member can watch 1st movie whose start time is 1 and end time is 5, and 5th movie whose start time is 6 and end time is 9. The second member can watch the movie 4th movie with a start time 2 and end time 4, and 2nd movie with start time 8 and end time 10. In this way total number of movies club members will watch entirely will be 4.

Input: N = 5, K = 1, movies = {{1, 5}, {8, 10}, {3, 6}, {2, 5}, {6, 9}}
Output: 2
Explanation: The first member can watch 1st movie whose start time is 1 and end time is 5 and 5th movie whose start time is 6 and end time is 9.

Approach: To solve the problem, follow the below idea:

The idea is to sort the movies by their start time. Then assign the first K movies to the K members. Now iterate over the remaining movies. For the ith movie, starting from (K+1)th movie, we compare the start of this movie with minimum end time of K assigned movies. If the minimum end time is less than or equal to the start time of ith movie, then we can increment the answer by 1, since a member can watch the movie with minimum end time and after that he can be assigned the ith movie. If the minimum end is greater than ith movie, then it will not be possible for any of the members to finish their currently assigned movies till this point. So we compare the end time of ith movie with maximum end time among the K assigned movies, if the end time of ith movie is less than the maximum one, it will be optimal to assign the ith movie to the member instead of the movie with maximum end time. For finding the movie with minimum and maximum end time, it is optimal to use the set data structure. We will repeat this procedure for all the remaining movies and add the size of the set to the answer at the end.

Step-by-step algorithm:

  • Sort the movies according to the start time.
  • The first k movies are assigned to the members, and their end times are inserted into a multiset. Multiset will contain the movies assigned to K members.
  • Iterate over the remaining movies starting from the (K + 1)th movie.
    • Check if the start time of the current movie is greater than or equal to the minimum end time among the assigned movies. If true, increment the answer and remove the movie with minimum time and insert the movie with current time in the set.
    • If the start time is less than the minimum end time, compare the end time of the current movie with the maximum end time among the assigned movies. If the end time of the current movie is less than the maximum, replace the movie with maximum end time in the set.
  • Add the size of the set to the answer at the end, since it contains all the movies assigned to members and this can be watched at the end.

Below is the implementation of the approach:

C++
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

// Sorting function to sort movies based on start times
bool sortcol2(const vector<ll> &v1, const vector<ll> &v2)
{
    return v1[0] < v2[0];
}

// Function to optimize movie-watching schedule
void MovieFestivalII(int n, int k, vector<vector<ll>> &a)
{
    // Multiset to store end times of assigned movies
    multiset<int> st;

    // Variable to keep track of entirely watchable movies
    ll ans = 0;

    // Initialize multiset with end times of first k movies
    for (int i = 0; i < k; i++)
    {
        st.insert(a[i][1]);
    }

    // Iterate over the remaining movies
    for (int i = k; i < n; i++)
    {
        // Iterator pointing to minimum end time
        auto mn = st.begin();
        // Iterator pointing to maximum end time
        auto mx = st.rbegin(); 

        // If the start time of the current movie is after or equal to the minimum end time,
        // it can be entirely watched, so increment the count and update the multiset
        if (a[i][0] >= (*mn))
        {
            ans++;
            st.erase(mn);
            st.insert(a[i][1]);
        }
        // If the end time of the current movie is less than the maximum end time,
        // replace the movie with the maximum end time in the multiset
        else if (a[i][1] < (*mx))
        {
            st.erase(st.find(*mx));
            st.insert(a[i][1]);
        }
    }

    // Print the total number of entirely watchable movies
    cout << ans + st.size() << "\n";
}

// Driver Code
int main()
{
    int n=5, k=2;

    // Vector to store movie start and end times
    vector<vector<ll>> a={{1,5},{8,10},{3,6},{2,5},{6,9}};

    // Sort movies based on start times
    sort(a.begin(), a.end(), sortcol2);

    // Call the function to optimize movie-watching schedule
    MovieFestivalII(n, k, a);
}
Java
import java.util.*;

public class MovieFestivalII {

    // Sorting function to sort movies based on start times
    static class MovieComparator
        implements Comparator<long[]> {
        public int compare(long[] v1, long[] v2)
        {
            return Long.compare(v1[0], v2[0]);
        }
    }

    // Function to optimize movie-watching schedule
    static void movieFestivalII(int n, int k,
                                List<long[]> a)
    {
        // PriorityQueue to store end times of assigned
        // movies
        PriorityQueue<Long> pq = new PriorityQueue<>();

        // Variable to keep track of entirely watchable
        // movies
        long ans = 0;

        // Iterate over the movies
        for (int i = 0; i < n; i++) {
            long startTime = a.get(i)[0];
            long endTime = a.get(i)[1];

            // Remove movies that end before the current
            // movie's start time
            while (!pq.isEmpty()
                   && pq.peek() < startTime - 1) {
                pq.poll();
            }

            // If there are fewer than k movies currently
            // playing, add the current movie
            if (pq.size() < k) {
                pq.add(endTime);
                ans++;
            }
            else {
                // If the earliest ending movie finishes
                // before the current movie starts, replace
                // it
                if (!pq.isEmpty()
                    && pq.peek() < startTime) {
                    pq.poll();
                    pq.add(endTime);
                    ans++;
                }
            }
        }

        // Print the total number of entirely watchable
        // movies
        System.out.println(ans);
    }

    // Driver Code
    public static void main(String[] args)
    {
        int n = 5, k = 2;

        // List to store movie start and end times
        List<long[]> a = Arrays.asList(
            new long[] { 1, 5 }, new long[] { 8, 10 },
            new long[] { 3, 6 }, new long[] { 2, 5 },
            new long[] { 6, 9 });

        // Sort movies based on start times
        a.sort(new MovieComparator());

        // Call the function to optimize movie-watching
        // schedule
        movieFestivalII(n, k, a);
    }
}

// This code is contributed by rambabuguphka
Python
import heapq

# Function to optimize movie-watching schedule
def movie_festival_ii(n, k, a):
    # Sorting function to sort movies based on start times
    def movie_comparator(v1, v2):
        return v1[0] - v2[0]

    # PriorityQueue to store end times of assigned movies
    pq = []

    # Variable to keep track of entirely watchable movies
    ans = 0

    # Iterate over the movies
    for i in range(n):
        startTime = a[i][0]
        endTime = a[i][1]

        # Remove movies that end before the current movie's start time
        while pq and pq[0] < startTime - 1:
            heapq.heappop(pq)

        # If there are fewer than k movies currently playing, add the current movie
        if len(pq) < k:
            heapq.heappush(pq, endTime)
            ans += 1
        else:
            # If the earliest ending movie finishes before the current movie starts, replace it
            if pq and pq[0] < startTime:
                heapq.heappop(pq)
                heapq.heappush(pq, endTime)
                ans += 1

    # Print the total number of entirely watchable movies
    print(ans)

# Sample input
n = 5
k = 2

# List to store movie start and end times
a = [[1, 5], [8, 10], [3, 6], [2, 5], [6, 9]]

# Sort movies based on start times
a.sort(key=lambda x: x[0])

# Call the function to optimize movie-watching schedule
movie_festival_ii(n, k, a)
C#
using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    // Function to optimize movie-watching schedule
    public static void MovieFestivalII(int n, int k, List<List<long>> a)
    {
        // Sorted dictionary to store end times of assigned movies
        SortedDictionary<long, int> st = new SortedDictionary<long, int>();

        // Variable to keep track of entirely watchable movies
        long ans = 0;

        // Initialize dictionary with end times of first k movies
        for (int i = 0; i < k; i++)
        {
            if (!st.ContainsKey(a[i][1]))
                st.Add(a[i][1], 0);
            st[a[i][1]]++;
        }

        // Iterate over the remaining movies
        for (int i = k; i < n; i++)
        {
            // Get the minimum end time
            var min = st.First().Key;
            // Get the maximum end time
            var max = st.Last().Key;

            // If the start time of the current movie is after or equal to the minimum end time,
            // it can be entirely watched, so increment the count and update the dictionary
            if (a[i][0] >= min)
            {
                ans++;
                if (st.ContainsKey(min))
                {
                    if (st[min] == 1)
                        st.Remove(min);
                    else
                        st[min]--;
                }
                if (!st.ContainsKey(a[i][1]))
                    st.Add(a[i][1], 0);
                st[a[i][1]]++;
            }
            // If the end time of the current movie is less than the maximum end time,
            // replace the movie with the maximum end time in the dictionary
            else if (a[i][1] < max)
            {
                if (st.ContainsKey(max))
                {
                    if (st[max] == 1)
                        st.Remove(max);
                    else
                        st[max]--;
                }
                if (!st.ContainsKey(a[i][1]))
                    st.Add(a[i][1], 0);
                st[a[i][1]]++;
            }
        }

        // Print the total number of entirely watchable movies
        Console.WriteLine(ans + st.Count);
    }

    // Driver Code
    public static void Main(string[] args)
    {
        int n = 5, k = 2;

        // List to store movie start and end times
        List<List<long>> a = new List<List<long>>()
        {
            new List<long>() {1, 5},
            new List<long>() {8, 10},
            new List<long>() {3, 6},
            new List<long>() {2, 5},
            new List<long>() {6, 9}
        };

        // Sort movies based on start times
        a.Sort((x, y) => x[0].CompareTo(y[0]));

        // Call the function to optimize movie-watching schedule
        MovieFestivalII(n, k, a);
    }
}
JavaScript
// Function to optimize movie-watching schedule
function movie_festival_ii(n, k, a) {
    // Sorting function to sort movies based on start times
    function movie_comparator(v1, v2) {
        return v1[0] - v2[0];
    }

    // PriorityQueue to store end times of assigned movies
    let pq = [];

    // Variable to keep track of entirely watchable movies
    let ans = 0;

    // Iterate over the movies
    for (let i = 0; i < n; i++) {
        let startTime = a[i][0];
        let endTime = a[i][1];

        // Remove movies that end before the current movie's start time
        while (pq.length > 0 && pq[0] < startTime - 1) {
            pq.shift();
        }

        // If there are fewer than k movies currently playing, add the current movie
        if (pq.length < k) {
            pq.push(endTime);
            ans += 1;
        } else {
            // If the earliest ending movie finishes before the current movie starts, replace it
            if (pq.length > 0 && pq[0] < startTime) {
                pq.shift();
                pq.push(endTime);
                ans += 1;
            }
        }
    }

    // Print the total number of entirely watchable movies
    console.log(ans);
}

// Sample input
let n = 5;
let k = 2;

// List to store movie start and end times
let a = [[1, 5], [8, 10], [3, 6], [2, 5], [6, 9]];

// Sort movies based on start times
a.sort((x, y) => x[0] - y[0]);

// Call the function to optimize movie-watching schedule
movie_festival_ii(n, k, a);

Output
4

Time Complexity: O(N * logK), where N is the number of movies and K is the number of members.
Auxiliary Space: O(K)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads