At the hospital n people are on a waiting list for a kidney’s transplant. We have the information about the compatibility between these people as a directed graph: compatible[i] is the set of people to which i can donate. Given this information, we want to maximize the number of people that receive a new kidney: anyone who gives a kidney must receive one, and no person receives more than one kidney.  Print the transplants (transplants) as a list of lists, where transplants[i][j] is 1 if person i donates to person j, and 0 otherwise.

# Data
num_people = 8  # number of people
compatible = [  # 1-based indexing, compatible[i] is the list of people to which i can donate
    [2, 3],
    [1, 6],
    [1, 4, 7],
    [2],
    [2],
    [5],
    [8],
    [3]
]
# End of data

# Import libraries
from cpmpy import *
import json

# Decision variables
transplants = boolvar(shape=(num_people, num_people))  # transplants[i][j] is True if i donates to j

# Model setup
model = Model()

# Constraints for the transplant pairs
for i in range(num_people):
    # Anyone who gives a kidney must receive one
    gives_kidney = sum(transplants[i, :]) >= 1
    receives_kidney = sum(transplants[:, i]) >= 1
    model += gives_kidney.implies(receives_kidney)

    # Each person can donate to at most one person and receive from at most one person
    can_donate_once = sum(transplants[i, :]) <= 1
    can_receive_once = sum(transplants[:, i]) <= 1
    model += can_donate_once & can_receive_once

    # Compatibility constraint: if i can't donate to j, then transplants[i][j] must be 0 (adjust for 0-based indexing)
    model += [transplants[i, j] == 0 for j in range(num_people) if j + 1 not in compatible[i]]

# Objective: maximize the number of transplants
model.maximize(sum(transplants))

# Solve
model.solve()

# Print the solution
solution = {"transplants": transplants.value().tolist()}
print(json.dumps(solution))
# End of CPMPy script


A magic square is an n x n grid (n != 2) such that each cell contains a different integer from 1 to n^2 and the sum of the integers in each row, column and diagonal is equal. Find a magic square for size 4, knowing that the sum of integers of each row, column and diagonal has to be equal to n(n^2+ 1)/2 (integer).  Print the magic square as a list of lists (square).

# Import libraries
from cpmpy import *
import json

# Parameters
n = 4  # size of the magic square
magic_sum = n * (n**2 + 1) // 2  # sum of each row, column and diagonal

# Decision Variables
square = intvar(1, n ** 2, shape=(n, n))  # the magic square

# Constraints
model = Model()

# All numbers in the magic square must be different
model += AllDifferent(square)

# The sum of the numbers in each row must be equal to the magic sum
for i in range(n):
    model += sum(square[i, :]) == magic_sum

# The sum of the numbers in each column must be equal to the magic sum
for j in range(n):
    model += sum(square[:, j]) == magic_sum

# The sum of the numbers in the main diagonal must be equal to the magic sum
model += sum(square[i, i] for i in range(n)) == magic_sum

# The sum of the numbers in the other diagonal must be equal to the magic sum
model += sum(square[i, n - 1 - i] for i in range(n)) == magic_sum

# Solve
model.solve()

# Print the solution
solution = {"square": square.value().tolist()}
print(json.dumps(solution))
# End of CPMPy script


In graph theory, an independent set is a set of vertices in a graph, no two of which are adjacent. A maximal independent set is an independent set that is not a subset of any other independent set. A graph may have many maximal independent sets of widely varying sizes: find a maximal independent set for the data provided. The data provides an array containing for each node of the graph the set of adjacent nodes.  Print whether each node is included in the maximal independent set (nodes).

# Data
n = 8  # number of nodes in the graph
adjacency_list = [  # adjacency list for each node in the graph
    [2, 3, 7],
    [1, 4, 8],
    [1, 4, 5],
    [2, 3, 6],
    [3, 6, 7],
    [4, 5, 8],
    [1, 5, 8],
    [2, 6, 7]
]
# End of data

# Import libraries
from cpmpy import *
import json

# Create a binary decision variable for each node to indicate if it's included in the independent set
nodes = boolvar(shape=n)

# Model setup
model = Model()

# Constraint: No two adjacent nodes can both be in the independent set
for i, neighbors in enumerate(adjacency_list):
    for neighbor in neighbors:
        # Subtract 1 to adjust for 1-based indexing in the data
        neighbor_idx = neighbor - 1
        # Ensure that for every edge, at least one of its endpoints is not in the independent set
        model += ~(nodes[i] & nodes[neighbor_idx])

# Objective: Maximize the number of nodes in the independent set
model.maximize(sum(nodes))

# Solve
model.solve()

# Print the solution
solution = {"nodes": nodes.value().tolist()}
print(json.dumps(solution))
# End of CPMPy script


Alice has to give Bob change of 199 euros. She has 6 different types of coins of different value ([1, 2, 5, 10, 25, 50]) and she has a certain number of coins of each value available ([20, 10, 15, 8, 4, 2]). How can the change be composed with the available coins minimizing the number of coins used?  Print the number of coins of each type to give to Bob (coin_counts).

# Import libraries
from cpmpy import *
import json

# Parameters
amount = 199  # amount of money to give to Bob
n = 6  # number of types of coins
types_of_coins = [1, 2, 5, 10, 25, 50]  # value of each type of coin
available_coins = [20, 10, 15, 8, 4, 2]  # number of available coins of each type

# Decision Variables
coin_counts = intvar(0, 20, shape=n)  # number of coins of each type to give to Bob

# Constraints
model = Model()

# The sum of the coins given to Bob must be equal to the amount of money to give him
model += sum(coin_counts[i] * types_of_coins[i] for i in range(n)) == amount

# The number of each type of coin given to Bob must not exceed the available coins
for i in range(n):
    model += coin_counts[i] <= available_coins[i]

# Objective: Minimize the total number of coins given to Bob
model.minimize(sum(coin_counts))

# Solve
model.solve()

# Print the solution
solution = {"coin_counts": coin_counts.value().tolist()}
print(json.dumps(solution))
# End of CPMPy script


# Source description: Steven S. Skiena's The Algorithm Design Manual

Consider the following scheduling problem. Imagine you are a highly-in- demand actor, who has been presented with offers to star in n different movie projects under development. Each offer comes specified with the first and last day of filming. To take the job, you must commit to being available throughout this entire period. Thus, you cannot simultaneously accept two jobs whose intervals overlap. For an artist such as yourself, the criteria for job acceptance is clear: you want to make as much money as possible. Because each of these films pays the same fee per film, this implies you seek the largest possible set of jobs (intervals) such that no two of them conflict with each other.  Input is a list of movies along with their first and last day of filming  Print the number of movies accepted (num_selected_movies) as well as which movies are accepted (selected_movies) as a list of 0s and 1s, where 1 indicates that the movie is selected and 0 indicates that it is not selected (in the order of the input list).

# Data
movies = [  # title, start, end
    ["Tarjan of the Jungle", 4, 13],
    ["The Four Volume Problem", 17, 27],
    ["The President's Algorist", 1, 10],
    ["Steiner's Tree", 12, 18],
    ["Process Terminated", 23, 30],
    ["Halting State", 9, 16],
    ["Programming Challenges", 19, 25],
    ["Discrete Mathematics", 2, 7],
    ["Calculated Bets", 26, 31]
]
# End of data

# Import libraries
from cpmpy import *
import json

# Parameters
num_movies = len(movies)

# Decision Variables
selected_movies = boolvar(shape=num_movies, name="selected_movies")  # 1 if the movie is selected, 0 otherwise
num_selected_movies = sum(selected_movies)  # Number of selected movies

# Model
model = Model()

# Add constraint for non-overlapping movie schedules
for i in range(num_movies):
    for j in range(num_movies):
        # Check if the intervals overlap for each pair of movies
        if (i != j  # Different movies
                and movies[i][2] > movies[j][1]  # Movie i ends after movie j starts
                and movies[j][2] > movies[i][1]  # Movie j ends after movie i starts
        ):
            # Then, the movies cannot be selected together
            model += selected_movies[i] + selected_movies[j] <= 1

# Objective: Maximize the number of selected movies
model.maximize(num_selected_movies)

# Solve
model.solve()

# Print
solution = {"num_selected_movies": model.objective_value(),
            "selected_movies": selected_movies.value().tolist()}
print(json.dumps(solution))
# End of CPMPy script


There are 13 people. 4 of them are male. They randomly enter a room one at a time. Find a way that the males and females enter so that the ratio of females to males in the room at any one time is no greater than 7/3?  Print the sequence of people entering the room (sequence), where 0 represents male and 1 represents female.

# Import libraries
from cpmpy import *
import json

total_people = 13
num_males = 4

# Decision variable: 0 for male, 1 for female
sequence = boolvar(shape=total_people)

# Constraints
model = Model()

# Ensure exactly number of males and females
model += [sum(sequence) == total_people - num_males]

# Add constraints for the ratio at each point in the sequence
for i in range(1, total_people):
    total_females_so_far = sum(sequence[:i])
    total_males_so_far = i - sum(sequence[:i])
    # Number of females to males is no greater than 7/3, or 3 times the females is less than or equal to 7 times the males
    model += (3 * total_females_so_far) <= (7 * total_males_so_far)

# Solve
model.solve()

# Print the solution
solution = {"sequence": sequence.value().tolist()}
print(json.dumps(solution))
# End of CPMPy script


Out of the set of integers 1,...,100 you are given ten different integers ([81 21 79  4 29 70 28 20 14  7]). From this set A of ten integers you can always find two disjoint non-empty subsets, S and T, such that the sum of elements in S equals the sum of elements in T. Note: S union T does not need to be all ten elements of A. Find sets S and T for the given set A.  Print which elements are in S (in_S) and which elements are in T (in_T), with 2 lists of length 10, where 1 means that the element is in the subset and 0 means that it is not.

# Import libraries
from cpmpy import *
import json

# Parameters
A = [81, 21, 79, 4, 29, 70, 28, 20, 14, 7]

# Decision variables: 1 if an element is in the subset, 0 otherwise
in_S = boolvar(shape=len(A))
in_T = boolvar(shape=len(A))

# Model setup
model = Model()

# Constraint: sum of elements in S equals sum of elements in T
model += (sum(in_S * A) == sum(in_T * A))

# S and T are disjoint, so there is no element that is in both S and T
model += (sum(in_S * in_T) == 0)

# S and T are non-empty
model += (sum(in_S) > 0)
model += (sum(in_T) > 0)

# Solve
model.solve()

# Print the solution
solution = {"in_S": in_S.value().tolist(), "in_T": in_T.value().tolist()}
print(json.dumps(solution))
# End of CPMPy script


A bank van had several bags of coins, each containing either 16, 17, 23, 24, 39, or 40 coins (there are multiple bags of the same kind). While the van was parked on the street, thieves stole some bags. A total of 100 coins were lost. It is required to find how many bags were stolen for each type of coin bag.  Print the number of bags stolen for each type of coins (bags).

# Import libraries
from cpmpy import *
import json

total_coins_lost = 100
coin_numbers = [16, 17, 23, 24, 39, 40]

# Decision variables
# The number of bags stolen for each type of coins
bags = intvar(0, total_coins_lost, shape=len(coin_numbers))

# Constraints
model = Model()

# The total number of coins lost is equal to the sum of the coins in the stolen bags
model += sum([bags[i] * coin_numbers[i] for i in range(len(coin_numbers))]) == total_coins_lost

# Solve
model.solve()

# Print the solution
solution = {"bags": bags.value().tolist()}
print(json.dumps(solution))
# End of CPMPy script


Following a robbery at Sparkles the Jeweller’s, Inspector Korner of the Yard interviewed six of the usual suspects. He knew that the getaway car had been barely big enough to hold two, so he reckoned that at least four of them were innocent - but which ones? He also supposed that the innocent ones would tell the truth, while the guilty one or ones would lie. What they actually said was: - ARTIE: "It wasn't me." - BILL: "Crackitt was in it up to his neck." - CRACKITT: "No I wasn't." - DODGY: "If Crackitt did it, Bill did it with him." - EDGY: "Nobody did it alone." - FINGERS: "That’s right: it was Artie and Dodgy together." If the good inspector’s suppositions were correct, who is guilty?  Print whether each suspect is guilty or not (artie, bill, crackitt, dodgy, edgy, fingers).

# Import libraries
from cpmpy import *
import json

# Decision Variables for each suspect representing if they are guilty
artie = boolvar(name="Artie")
bill = boolvar(name="Bill")
crackitt = boolvar(name="Crackitt")
dodgy = boolvar(name="Dodgy")
edgy = boolvar(name="Edgy")
fingers = boolvar(name="Fingers")
suspects = [artie, bill, crackitt, dodgy, edgy, fingers]

# Constraints
model = Model()

# At most two are guilty because the getaway car was small
model += sum(suspects) <= 2

# Statement Constraints; if the suspect is guilty, they are lying, so their statement is false

# Artie: "It wasn't me."
artie_statement = ~artie
model += artie == ~artie_statement

# Bill: "Crackitt was in it up to his neck."
bill_statement = crackitt
model += bill == ~bill_statement

# Crackitt: "No I wasn't."
crackitt_statement = ~crackitt
model += crackitt == ~crackitt_statement

# Dodgy: "If Crackitt did it, Bill did it with him."
dodgy_statement = crackitt.implies(bill)
model += dodgy == ~dodgy_statement

# Edgy: "Nobody did it alone."
edgy_statement = sum(suspects) > 1
model += edgy == ~edgy_statement

# Fingers: "That’s right: it was Artie and Dodgy together."
fingers_statement = artie & dodgy
model += fingers == ~fingers_statement

# Solve
model.solve()

# Print the solution
solution = {
    "artie": int(artie.value()),
    "bill": int(bill.value()),
    "crackitt": int(crackitt.value()),
    "dodgy": int(dodgy.value()),
    "edgy": int(edgy.value()),
    "fingers": int(fingers.value())
}
print(json.dumps(solution))
# End of CPMPy script