- ← Back
- 2020 - R1
- 2020 - R2
- 2020 - R3
- 2021 - R1
- 2021 - R2
- 2021 - R3
- 2021 - R4
- 2022 - R1
- 2022 - R2
- 2022 - R3
- 2023 - R1
- 2023 - R2
- 2023 - R3
- 2024 - R1
- 2024 - R2
- 2024 - R3
- Scoreboard
- Scoreboard
Container Service Preheating
Limits: 10 sec., 1024 MiB
In cloud computing environments, virtual machines (VMs) host containerized microservices. When users request to launch a container, the scheduler initially allocates containers to existing VMs, provisioning additional VMs if necessary. However, creating new VMs takes time and it can introduce additional latency for clients. This can result in a poor quality of experience (QoE). We can mitigate this by purchasing a set of VMs before the actual container requests. This strategy is known as “preheating”.
The demand for new containers is unpredictable. Various VM types are available for purchase. Each type of VM has corresponding resource specifications (CPU and memory) and price per unit of time. For each container request, you must decide which VM to run the container on. Once a container is associated with a VM, the container runs on it, occupying a certain amount of resources until the container is deleted. After a container is deleted, the resources are released and can be used by other containers.
You need to determine the optimal number of VMs, the optimal time to pre-provision them and how to place containers into those VMs in order to minimize the total cost, which has two components:
Resource Reservation Cost (RC): This is the cost of running the VMs.
Container Launch Delay Cost (DC): This is the cost incurred when a user request cannot be immediately fulfilled due to a lack of available VMs.
You can find more information about scoring in the Scoring section of the problem statement.
Please note that this is an interactive problem. Your solution will communicate with the interactor through the stdin/stdout streams.
Interaction protocol
The first line of the input contains two integers m and d — the number of available VM types and VM creation delay. The following m lines contain the description of the types. Each line contains three space-separated integers: cpui, memi, and pricei which represent the number of CPU units, the memory, and the price of the VM type. The VM types are enumerated from 1 to m.
The next line contains a single integer t — the number of time steps of the interaction. The first line of each time step contains an integer ej — the number of events during this time step. In case if ej=0, it is followed by an integer cntj. This means that there are no events on the current time step, as well as cntj−1 following time steps (cntj empty time steps in total). There will be no input for any of the next cntj−1 time steps and you have to process each of them in a single batch. For each of the cntj time steps you have to print a list of actions as described below.
In case if ej>0, the following ej lines contain events for the current time step. There are two types of events:
1 idcontjk cpucontjk memcontjk: a new container creation request has arrived. The container is identified by idcontjk and requires cpucontjk CPU units and memcontjk memory. This request can be fulfilled immediately within the current time step.
2 idcontjk: a container with an identifier idcontjk must be shut down. The resources occupied by this container might be used during the next time step.
After your solution has read the information about the events during the current time step, you have to print a line with an integer aj — the number of actions that you want to perform during this time step. Then print aj lines, one for each action. There are three possible actions you can perform:
1 idvmjk typevmjk — start a new VM with an identifier idvmjk and a type typevmjk. This action takes d time steps, meaning the VM becomes available at time step x+d if provisioned at time step x.
2 idvmjk — shut down a VM with an identifier idvmjk. To perform this action, the VM with an identifier idvmjk should have no containers allocated before the beginning of this time step. If the last container on a VM is terminated at step x, the VM can be shut down starting from step x+1.
3 idcontjk idvmjk — allocate the container with an identifier idcontjk on a VM with an identifier idvmjk. To perform this action, the container with an identifier idcontjk has to not be yet allocated and the VM with an identifier idvmjk has to have at least cpucontidcontjk CPUs and memcontidcontjk memory available.
After printing aj lines with your actions, ensure the output is flushed, so that the interactor can read your actions and proceed with the next time step.
Please note, that if ej=0, you have to print cntj blocks of actions, one for each time step with no events. You should flush the output only after you printed actions for all cntj time steps. This is needed to improve the performance of the i/o of your solution.
If the interactor prints the value ej=−1 — this means that one of your actions during the previous
step was invalid. Your program has to exit immediately. In this case,
you will get the Wrong Answer
verdict.
After t time steps, the interactor prints a single integer et+1, which equals 0 if your last action is valid or -1 if the last action is invalid. Afterwards, the interaction is over and your solution must exit.
Input constraints
1≤m≤47,
1≤d≤40,
1≤cpui,cpucontjk≤105,
1≤memi,memcontjk≤2⋅106,
1≤pricei≤2⋅105,
1≤idcontjk≤109,
each container has a unique identifier,
1≤t≤2⋅107,
−1≤ej≤2.4⋅104,
1≤∑ej≤2.4⋅104.
1≤cntj≤20,
Output constraints
1≤aj≤3⋅107,
∑aj≤3⋅107,
1≤idvmjk≤109,
each VM should have a unique identifier,
1≤typevmjk≤m.
Interaction example
Interactor output | Solution Output | Description |
---|---|---|
2 4 |
We have two VM types which warm up for 4 time steps. | |
8 1024 1 |
8 CPUs, 1024 memory, cost 1 per time unit. | |
32 4096 2 |
32 CPUs, 4096 memory, costs 2 per time unit. | |
14 |
The interaction will last for 14 time units. | |
0 2 |
No events for the first 2 time steps. | |
2 |
Two actions on the first time step. | |
1 1 2 |
Start VM of type 2. | |
1 2 2 |
Start VM of type 2. | |
0 |
Do nothing on time step 2. | |
0 1 |
No events on time step 3. | |
0 |
No actions on time step 3. | |
1 |
One event on time step 4 | |
1 1 2 32 |
Create a container with 2 CPUs and 32 units of memory. | |
0 |
The VMs are not ready yet, do nothing for now. | |
0 1 |
No events on time step 5. | |
1 |
One action. | |
3 1 2 |
Allocate container 1 to the VM 2. | |
2 |
Two events on time step 6. | |
1 2 24 256 |
Container with 24 CPUs and 256 memory; | |
1 3 16 512 |
Container with 16 CPU, 512 memory. | |
3 |
Three actions. | |
3 3 1 |
Allocate container 3 to VM 1. | |
3 2 2 |
Allocate container 2 to VM 2. | |
1 3 1 |
Start a new VM of type 1. | |
0 6 |
No events on time steps 7, 8, 9, 10, 11, 12. | |
0 |
No actions on time step 7. | |
0 |
No actions on time step 8. | |
2 |
Two actions on time step 9. | |
1 4 1 |
Start new VM with type 1. | |
1 5 1 |
Start new VM with type 1. | |
0 |
No actions on time step 10. | |
0 |
No actions on time step 11. | |
1 |
One action on time step 12. | |
1 6 2 |
Start new VM with type 2. | |
6 |
Six events on time step 13. | |
1 5 8 1024 |
New container. | |
2 2 |
Shut down container 2. | |
2 1 |
Shut down container 1. | |
2 3 |
Shut down container 3. | |
1 6 8 1024 |
New container. | |
1 7 8 1024 |
New container. | |
3 |
Three actions on time step 13. | |
3 5 4 |
Allocate container 5 on VM 4. | |
3 6 5 |
Allocate container 6 on VM 5. | |
3 7 3 |
Allocate container 7 on VM 3. | |
0 1 |
No events on time steps 14. | |
2 |
Two actions on time step 14. | |
2 1 |
Shut down VM 1. | |
2 2 |
Shut down VM 2. |
Scoring
If on any time step your solution performs an invalid action, violates one of the output constraints, or fails to allocate one of the containers, it is considered to be incorrect and for such a test case you receive 0 points. Otherwise, your score is calculated as follows:
score=⌊TC⋅BPRC+DC⋅10⋅107⌋
Where:
TC is the total number of CPU time units in all container requests:
TC=∑(shutdownjk−allocjk)⋅cpucontjk
Where shutdownjk and allocjk are the time units of container shutdown and allocation to vm respectively. If the container didn’t shut down then shutdownjk=t+1 for such container.
BP is the best possible price per CPU between all VM types:
BP=minpricei⋅10−4cpui
RC is the Resource Reservation Cost, which is the total cost of running all the virtual machines. Suppose that in total you started v VMs, s-th of them was launched at time step VMstarts, stopped at time step VMends (if you didn’t stop a VM then VMends = t+1) and has type VMtypes. Then the Resource Reservation Cost equals:
RC=v∑s=1(VMends−VMstarts)⋅priceVMtypes⋅10−4
DC is the Container Launch Delay Cost. Suppose that in total there were c container requests, f-th of them appeared at time step Cstartf, and was allocated to a VM at the time step Callocf. Then the Container Launch Delay Cost equals:
DC=c∑f=1(1.1(Callocf−Cstartf)−1)
Submissions
The execution time limit is 10 seconds per test case, and the memory limit is 1024 mebibytes.
The code size limit is 64 kibibytes.
The compilation time limit is 1 minute.
There are 20 provisional test cases. Your submissions will be evaluated on the provisional set during the submission phase.
You can submit your code once every 30 minutes, and you will get feedback with your score for each of the provisional tests.
There will be 200 test cases in the final testing after the submission phase is over. Please note that provisional tests are not included in the final testing. The final results will be announced in one week.
Quick start
Check the sample solution, which implements a very simple algorithm: for each container request find a VM type that can host this container with minimal price, launch a VM with this time, wait for it to warm up and then host the container on this VM. After container shut down event, shut down the VM for this container as well.
Local testing
You have access to the ganerator, checker and scorer, as well as a tool for local testing of your solution. All of them are implemented using Algotester Library and Algotester Generator Library. You can download the source codes of both libraries using the following links: algotester.h, algotester_generator.h. Both files should be places into the same directory as problem source codes.
Please note that the generator, checker and scorer provided to you are actually used to score your solutions on the Algotester website. You can use the source codes to clarify any questions that you have about the test cases, scoring, or the interaction protocol.
All test cases, including provisional and final sets, are generated by the generator. You can use the generator to create tests for local testing by using a few simple steps:
Save the generator source code to a file named
generator.cpp
Compile the source code:
g++ generator.cpp -O2 -o generator
Generate a test case
./generator <seed>
This will print a test case for a specific seed to standard output.
The purpose of the checker in this problem is to read the test input data and interact with your solution: provide it with test data and read your solution’s output. The checker also checks your solution for validity: it will print an error message to stdout if your solution is incorrect on a given test case. If the stdout of the checker is empty, this means that your solution is correct on the current test case.
The scorer reads the test case input data as well as an interaction log created by the checker and scores your solution. Please note that the scorer assumes that the solution provided correct outputs for the test case, i.e. the checker did not print anything into stdout.
The tool for local testing automates the process of managing the solution, checker, scorer and generator. In order to use the local testing tool, follow these steps:
Save the interactor source code to a file named
interactor.py
Save the checker source code to a file named
checker.cpp
Save the scorer source code to a file named
scorer.cpp
Save the generator source code to a file named
generator.cpp
Compile the checker, scorer and generator source codes:
g++ checker.cpp -O2 -o checker g++ scorer.cpp -O2 -o scorer g++ generator.cpp -O2 -o generator
Prepare your solution for execution. (Compile the code for compiled languages (C++, Java, C#). Do nothing for interpreted languages (Python, Node).
Write down the command for the solution execution. (For example: C++ - "
./solution
", Python - "python solution.py
", Java - "java solution.class
".)Pass the command and the path to the input file to the interactor. Use the "
--help
" command to find out what the tool can do.python interactor.py --solution "./solution" --test_file "in.txt" python interactor.py --solution "python solution.py" --test_file "in.txt" --seed 47 python interactor.py --help
The interactor will generate the test (in case that
seed
is specified), launch your solution with the checker, and then, if checker found no errors in your solution, launch scorer to calculate your score for the test. The interactor prints a detailed log of the process to stdout.
Submit a solution
To submit solutions, you have to register first.
Register