Big HW2 2025
Big HW2 2025
General information
● For this project, you will work in teams of 2 people (or alone).
● The project must be submitted on the Moodle platform (curs.upb.ro) in the dedicated
assignment (on the instance of the DSA course). If there are any issues when uploading to
or downloading from the platform, contact your lab assistant via Teams or email.
● The project must be submitted no later than May 26, 2025, at 8:00 AM. No late
submissions will be accepted.
● You will be asked details about your solutions during the following lab. Projects not
presented at the following lab will not be graded!
● The final project submission MUST have the following structure and respect the
following constraints. Failure to respect these indications will lead to the loss of points
from your solutions.
1. only the source files of your project (.cpp and .h) — not object files (.o),
Codeblocks (.cbp), executables (.exe) or other extensions accepted; Please put
each exercise in a separate folder as shown in the following picture! (Note: the
data structures shown in the picture are randomly chosen, they are not the real
ones that you should use for the corresponding exercises of the current
homework).
2. only one upload per team is enough; otherwise, the Moss software will compare
your solution against that of your teammate;
3. a README file in which you specify (in a few words) all the features of your
project, with instructions on how to use them. If there are requirements that are
not functional, you can suggest possible solutions (and maybe get some points).
● For all questions regarding the project, use the dedicated Microsoft Teams channel
(recommended to create a new post on the Teams group so that everyone can see the
question & the answer). Don’t forget to mention @General (to notify everyone) or
@TeacherName.
● You need to use both graphs and binary trees as types of data structures in the current
homework. If you use a graph to solve an exercise you cannot use a binary tree as well in
the same exercise.
● Warning: we will use plagiarism detection software on your submissions (Stanford’s tool
Moss). Copied homework (more than 20% similarity between your code and a different
source - Internet, colleagues etc.) or the ones generated with the help of AI (ChatGPT,
Gemini, Claude or any similar tool) will be marked with 0 points. Any other fraud
attempt or technique will be subject to the university’s rules
(https://upb.ro/wp-content/uploads/2022/11/Regulament-org-studii-univ-licenta_2024.pdf
)
! Observation: You MUST use the data structures we created (not the standard ones of C++) as
header files and optionally other exercises that we used in class. Failure to do this will lead to
partial or total loss of points for that exercise.
You are designing a digital combination lock. The lock is opened when a specific sequence of n
digits is entered. Each digit must be in the range [0,k−1][0,k−1].
However, the lock checks the last n digits every time you input a new digit, not just at the end.
For example, suppose the correct code is "345" and you type in "012345":
● After entering 0: last 1 digit is "0" (incorrect) (we check 1 digit since we don’t have 3
yet).
● After entering 1: last 2 digits are "01" (incorrect) (we check 2 digits since we don’t have
3 yet).
● After entering 2: last 3 digits are "012" (incorrect) (further we will check 3 digits as
stated in the exercise)
● After entering 3: last 3 digits are "123" (incorrect).
● After entering 4: last 3 digits are "234" (incorrect).
● After entering 5: last 3 digits are "345" (correct — the lock opens).
Your task is:
Create the shortest possible sequence of digits that guarantees the lock will eventually open, no
matter what the correct code is.
Example 1:
Input: n = 1, k = 2
Output: "01" or "10"
Explanation:
Every 1-digit password ("0" or "1") is checked during input.
Example 2:
Input: n = 2, k = 2
Output: "00110", "01100", or similar
Explanation:
All two-digit passwords ("00", "01", "10", "11") appear in the sliding window as you type.
Constraints:
● 1≤n≤41≤n≤4
● 1≤k≤101≤k≤10
● 1≤kn≤40961≤kn≤4096
Points:
● 0.5p - Reading input correct
● 2.5 p – The algorithm
● 0.5p – Validation, correct display, handle of the different cases
● Obs: lack of validation of multiple corner cases can lead to the loss of all or partial points
from the algorithm
Daenerys Targaryen is conquering the cities of Essos, and she must ensure that all the cities are
under her control using her dragons.
The cities are connected in a hierarchy, with each city potentially ruling over smaller cities but
being itself under the control of a bigger city. A city can have only maximum two immediately
subordinate cities.
Daenerys can station a dragon in a city. A dragon stationed in a city can oversee:
Given the root city (like Meereen) at the top of the hierarchy, determine the minimum number of
dragons Daenerys needs to deploy to ensure every city is either directly protected or watched
over by a neighboring dragon.
Return the minimum number of dragons needed to completely secure her new empire.
Example 1:
Input: Meereen = [0,0,null,0,0]
Output: 1 Dragon
Explanation:
Meereen
🐉
/
/ \
0 0
Example 2
Input: Meereen = [0,0,null,0,null,0,null,null,0]
Output : 2 Dragons
Explanation:
Meereen
🐉
/
/
0
🐉
/
\
0
Constraints:
● Node.val = 0
Points:
● 0.5p - Reading input correct
● 2 p – The algorithm
● 0.5p – Validation, correct display, handle of the different cases
● Obs: lack of validation of multiple corner cases can lead to the loss of all or partial points
from the algorithm
3. Core Scheduling: Minimizing Energy with Deadlines and Dependency Cycles (3.5p)
Introduction
Modern computing systems often feature multiple processing cores with varying performance
characteristics (speed) and power consumption rates. Efficiently scheduling tasks across these
heterogeneous cores is crucial, especially in real-time systems where tasks must be completed by
specific deadlines. A primary goal in mobile and embedded systems is to minimize energy
consumption while guaranteeing that all tasks meet their timing constraints and respect any
dependencies between them.
You are tasked with developing a scheduler for a set of computational tasks that need to be
executed on a system with multiple heterogeneous cores. Each task has a defined computational
workload, a deadline by which it must be completed, and potential dependencies on other tasks.
Each core type has a specific processing speed and a power consumption rate (energy consumed
per unit of time).
The goal is to find a schedule (an assignment of each task to a core, along with a start and end
time) that minimizes the total energy consumed by all cores while ensuring:
1. Dependency Constraints:
If Task A must complete before Task B can start (denoted A -> B), the scheduled end
time of Task A must be less than or equal to the scheduled start time of Task B. Tasks and
their dependencies can be modeled as a directed graph.
2. Deadline Constraints:
Every task must be completed on or before its specified deadline.
3. Core Constraints:
A single core can only execute one task at a time.
● Graph Traversal: Techniques that systematically traverse the graph are required to
identify strongly connected components or back-edges, which indicate cycles.
● Direct Mutual Dependency (2-Cycle): If the analysis reveals exactly two tasks, say Task
A and Task B, forming a direct mutual dependency (A -> B and B -> A), this represents a
special constraint. These two tasks must be scheduled to start at the exact same time, but
on different cores. This parallel execution constraint overrides the standard finish-to-start
dependency between only these two tasks. All other dependencies involving Task A or
Task B must still be respected. If this parallel execution is impossible (e.g., not enough
cores, violates deadlines, or conflicts with other dependencies), then no valid schedule
exists.
● Larger Cycles: If a cycle involves three or more tasks, a valid schedule satisfying all
constraints is considered impossible.
Energy Calculation
● The execution time of a task on a specific core is calculated as: Task Workload / Core
Speed
● The energy consumed by a task on a specific core is: Execution Time * Core Power Rate
● The total energy for a schedule is the sum of the energy consumed by all tasks
Input Format
Input will be provided via a text file named input.txt with the following structure:
N # Number of tasks
# Task Info (N lines): TaskID Workload Deadline
T1_ID T1_Workload T1_Deadline
T2_ID T2_Workload T2_Deadline
...
TN_ID TN_Workload TN_Deadline
M # Number of dependencies
# Dependency Info (M lines): From_TaskID To_TaskID
Dep1_From Dep1_To
Dep2_From Dep2_To
...
DepM_From DepM_To
● N, M, K - positive integers
● TaskIDs are positive integers (not necessarily sequential).
● Workload, Deadline, CoreSpeed, CorePowerRate - positive floating-point numbers.
● Dependencies are specified using the original TaskIDs.
● Core types are implicitly assigned IDs 0, 1, ..., K-1 based on their order in the input.
Output Format
Your program should output the results to the standard output.
Cycle Detection Output:
● Before other output, print messages related to cycle detection as described above
(warnings for cycles, confirmation of DAG status). Use standard error for warnings and
standard output for the DAG confirmation message. Ensure output buffers are flushed
appropriately so these messages appear in the correct order relative to subsequent output.
Example warning:
Warning: Cycle detected involving tasks (1-based IDs): { 2, 1 }
● If cycles are detected, indicate the attempt to proceed:
Attempting to schedule based on special cycle handling rules.
Scheduling Results:
● If a valid schedule is found:
○ Print the minimum total energy: Minimum Total Energy Consumed: XXX.XX
○ Print the schedule table and the details for each task (Task ID, Core ID, Start
Time, End Time, Energy)
● If no valid schedule is found:
Scheduling failed. No solution found that meets all deadlines.
Examples:
Test Case 1: Simple 2-Node Cycle, Schedulable
2
1 100 5.0
2 150 5.0
2
12
21
2
100 10
100 20
Explanation:
common_start = max(0,0,0)=0.
T0 Time=100/100=1.0,
T1 Time=150/100=1.5.
T0 End=1.0,
T1 End=1.5.
Deadlines (5.0) met.
Energy = (1.0*10) + (1.5*20) = 10 + 30 = 40.
common_start = 0.
T0 Time=100/100=1.0,
T1 Time=150/100=1.5.
T0 End=1.0,
T1 End=1.5.
Deadlines met.
Energy = (1.0*20) + (1.5*10) = 20 + 15 = 35
The state corresponding to Pair 2 (Energy=35) has lower energy and is processed first.
The goal state is reached with energy 35.00.
3
0 50 2.0
1 100 5.0
2 150 5.0
3
01
12
21
2
100 10
100 20
Explanation:
The cycle {1, 2} is detected and noted. Task 0 is acyclic.
Initially, only Task 0 is ready (no predecessors).
Now, the special 2-node cycle check runs. It finds pair (task 1, task 2).
External Predecessors: Task 1 needs Task 0 (index 0). Task 2 has no external predecessors
It tries scheduling the pair on different cores, starting no earlier than 0.5
● common_start = max(0.5, CT[0]=0.5, CT[1]=0.0) = 0.5. T1 Time=1.0, T2 Time=1.5. T1
End=1.5, T2 End=2.0. Deadlines (5.0) met. Energy = (1.0*10) + (1.5*20) = 10 + 30 = 40.
Total path energy = 5 + 40 = 45.
● common_start = max(0.5, CT[0]=0.5, CT[1]=0.0) = 0.5. T1 Time=1.0, T2 Time=1.5. T1
End=1.5, T2 End=2.0. Deadlines met. Energy = (1.0*20) + (1.5*10) = 20 + 15 = 35.
Total path energy = 5 + 35 = 40.
2
1 200 1.5
2 200 1.5
2
12
21
2
100 10
100 20
Explanation:
Cycle Detection: Cycle {1, 2} detected
Special check finds the pair (task 0, task 1).
Try scheduling in parallel:
● (Pair 1: T0 on C0, T1 on C1): common_start = 0. T0 Time=200/100=2.0, T1
Time=200/100=2.0. T0 End=2.0, T1 End=2.0. Deadlines (1.5) Missed.
● (Pair 2: T0 on C1, T1 on C0): common_start = 0. T0 Time=2.0, T1 Time=2.0. T0
End=2.0, T1 End=2.0. Deadlines (1.5) Missed.
Scheduling fails because the required parallel execution violates deadlines.
Test Case 4: 2-Node Cycle, Core Constraint Failure
2
1 100 5.0
2 150 5.0
2
12
21
1
100 10
Explanation:
● Cycle {1, 2} detected.
● Check if (numCoreTypes >= 2) immediately fails because there's only 1 core and a cycle
that needs to run in parallel.
● Proceeds to the regular task scheduling loop.
● Neither Task 1 nor Task 2 meets the standard to run
Scheduling fails because 1 core and a cycle that needs to run in parallel, no task can be scheduled
3
1 100 10.0
2 100 10.0
3 100 10.0
3
12
23
31
2
100 10
100 10
Explanation:
● Cycle Detection: Cycle {1, 2, 3} is detected
● 2-node check finds no applicable pairs we have multiple pairs and only two cores
● No task ever meets the standard readiness check because each task in the cycle requires a
predecessor that is also in the cycle and cannot be run in parallel
Scheduling fails because the cycle involves more nodes than cores.
3
1 100 1.0
2 500 4.0
3 100 1.0
1
12
2
200 40
150 30
Explanation:
Cycle Detection: No cycles detected.
Regular scheduling proceeds
● Tasks 1 and 3 are ready.
● Schedule Task 1: Core 0 (Time=0.5, E=20) vs Core 1 (Time=0.67, E=20). Core 0 chosen
(lower index tie-break). State E=20, F[1]=0.5, CT={0.5, 0.0}.
● Schedule Task 3: Core 0 (Start=0.5, End=1.0, E=20) vs Core 1 (Start=0.0, End=0.67,
E=20). Core 1 chosen (available earlier). State E=40, F[1]=0.5, F[3]=0.67, CT={0.5,
0.67}.
● Schedule Task 2: Needs Task 1. earliest_start_by_preds=0.5. Core 0 (Start=max(0.5,
0.5)=0.5, Time=2.5, End=3.0, E=100) vs Core 1 (Start=max(0.5, 0.67)=0.67, Time=3.33,
End=4.0, E=100). Core 0 chosen (lower index tie-break). State E=140, F[1]=0.5,
F[2]=3.0, F[3]=0.67, CT={3.0, 0.67}.
Goal state reached with minimum energy 140.00.
4
1 100 5.0
2 150 5.0
3 80 6.0
4 120 6.0
4
12
21
34
43
2
100 10
100 20
Test Case 8: Multiple Dependencies
5
1 100 10.0
2 80 12.0
3 120 12.0
4 150 15.0
5 50 18.0
5
12
13
24
34
45
2
100 10
120 8
4
1 100 3.0
2 400 4.0
3 100 6.0
4 200 7.0
3
12
13
24
2
50 10
200 100
Useful Links:
● https://www.geeksforgeeks.org/dependency-graph-in-compiler-design/
● https://www.geeksforgeeks.org/strongly-connected-components/
● https://www.geeksforgeeks.org/shortest-path-for-directed-acyclic-graphs/
● https://en.wikipedia.org/wiki/State_space_search
● https://people.eecs.berkeley.edu/~pabbeel/cs287-fa11/slides/search.pdf