0

Not sure if this is the right place get help with this kind of problem, but I am trying to solve this by coding so I'll try. If anyone knows about some better suited forum/place for this kind of problem, let me know.

I have a data frame that looks like this:

import pandas as pd


data = {
    "ID": [1, 2, 3, 4, 5, 6, 7....],
    "NAME": ["male_1", "male_2", "male_3", "male_4", "female_1", "female_2", "female_3"...],
    "M_F": ["M", "M", "M", "M", "F", "F", "F"...],
    "AGE": [9, 5, 8, 6, 10, 11, 9...],
    "GROUP": ["1,2,3", "1,2,3", "1,2,3", pd.NA, "5,6", "5,6", pd.NA...]
}


df = pd.DataFrame(data)

In r it can be written as

df <- data.frame(
  ID = c(1, 2, 3, 4, 5, 6, 7...),
  NAME = c("male_1", "male_2", "male_3", "male_4", "female_1", "female_2", "female_3"...),
  M_F = c("M", "M", "M", "M", "F", "F", "F"...),
  AGE = c(9, 5, 8, 6, 10, 11, 9..),
  GROUP = c("1,2,3", "1,2,3", "1,2,3", NA, "5,6", "5,6", NA...),
  stringsAsFactors = FALSE
)

And it something like this

| ID | NAME | M_F | AGE | GROUP |
| -- | ---- | --- | --- | ----- |
| 1  |male_1 | M| 9 | 1,2,3|
| 2  |male_2 | M| 5 | 1,2,3|
| 3  |male_3 | M| 8 | 1,2,3|
| 4  |male_4 | M| 6 | NA |
| 5  |female_1 |F|10|5,6|
| 6  |female_2 |F|11|5,6|
| 7  |female_3 |F|9|NA|
| . | . | . | . | .|

I have about 100 people in this data frame(length of DataFrame) , grouped as indicated by GROUP category in groups of up to 7 and some have no group (NAs). I need to place these people into huts/houses which can house 3, 4, 7 or 8 people. Number of these huts are as follows:

  • 4x hut with size 3
  • 13x hut with size 4
  • 4x hut with size 7
  • 4x hut with size 8

So I have a total housing capacity of 124(4 * 3 + 13 * 4 + 4 * 7 + 4 * 8) people for about 100 people, so there is some spare space. Criteria for placing people in these huts are as follows:

  1. Males and females have to be in separate huts
  2. Groups have to be respected, people with group = NA can be placed with any group, in any hut
  3. Difference in age between youngest and oldest in hut should be 4 years maximum

I am working on this problem in R, but I have little experience with Python as well, if that would be more comfortable for someone. Any help or ideas are appreciated. It is a passion project of mine, I am just trying to help out with some tedious task of manualy sorting these kids into huts on a summer camp :D
Cheers!

4

1 Answer 1

1

The following script uses the assign_huts function, which primarily uses a greedy algorithm with heuristics to assign people to huts. It works as follows *Picks a hut size from the available capacities.

  • Iterates over remaining people, selecting those who fit the age constraint and belong to the same group.
  • Adds them to the hut until full.
  • Assign person jwth group= NA to hit first found.

Complexity is O(n log n)


from itertools import combinations

huts = dict(3=4 , 4=13 , 7=4 , 8=4) # {capacity: number of huts}

def parse_groups(x):
    return set(map(int, x.split(","))) if pd.notna(x) else set()

df["GROUP_SET"] = df["GROUP"].apply(parse_groups)

df.sort_values(by=["GROUP", "AGE"], inplace=True)

def assign_huts(df, huts):
    assigned_hut = []
    remaining_p = df.to_dict(orient="records")
    
    while remaining_p:
        for hut_size, count in huts.items():
            for _ in range(count):
                if not remaining_p:
                    break

                hut = []
                available_people = remaining_p[:]

                # Prioritize keeping groups together
                while available_people and len(hut) < hut_size:
                    for p in available_people[:]:
                        if not hut or (max(x["AGE"] for x in hut) - min(x["AGE"] for x in hut) <= 4): # xhecing the difference between minimum and Maximun age 
                            hut.append(p)
                            available_people.remove(p)
                            remaining_p.remove(p)
                            if len(hut) == hut_size:
                                break
                
                assigned_hut.append(hut)

    return assigned_hut

males = df[df["M_F"] == "M"].copy()
females = df[df["M_F"] == "F"].copy()

male_huts = assign_huts(males, huts)
female_huts = assign_huts(females, huts)

You can use knapsack, which ensures huts are filled more efficiently than a greedy approach, and it works efficiently in large inputs. But has a complexity of O(n * W) where W is the Hut capacity. [Hut capacity is not necessary, as stated by you

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.