def find_matching(self):
        u"""Finds a matching in the bipartite graph.

        This is done using the Hopcroft-Karp algorithm with an implementation from the
        `hopcroftkarp` package.

        Returns:
            A dictionary where each edge of the matching is represented by a key-value pair
            with the key being from the left part of the graph and the value from te right part.
        """
        # The directed graph is represented as a dictionary of edges
        # The key is the tail of all edges which are represented by the value
        # The value is a set of heads for the all edges originating from the tail (key)
        # In addition, the graph stores which part of the bipartite graph a node originated from
        # to avoid problems when a value exists in both halfs.
        # Only one direction of the undirected edge is needed for the HopcroftKarp class
        directed_graph = {}  # type: Dict[Tuple[int, TLeft], Set[Tuple[int, TRight]]]

        for (left, right) in self._edges:
            tail = (LEFT, left)
            head = (RIGHT, right)
            if tail not in directed_graph:
                directed_graph[tail] = set([head])
            else:
                directed_graph[tail].add(head)

        matching = HopcroftKarp(directed_graph).maximum_matching()

        # Filter out the partitions (LEFT and RIGHT) and only return the matching edges
        # that go from LEFT to RIGHT
        return dict((tail[1], head[1]) for tail, head in matching.items() if tail[0] == LEFT)
Esempio n. 2
0
def get_departure_keys_product(rules=RULES,
                               tickets=TICKETS,
                               my_ticket=MY_TICKET):
    tickets_to_remove = set(i for i, ticket in enumerate(tickets)
                            if invalid(ticket, rules))

    n = len(tickets[0])
    rule_columns = {r: set(range(n)) for r in rules}
    for i, ticket in enumerate(tickets):
        if i in set(tickets_to_remove):
            continue
        for rule in rules:
            for j, v in enumerate(ticket):
                if not is_valid(v, rules[rule]):
                    rule_columns[rule].discard(j)

    matching = HopcroftKarp(rule_columns).maximum_matching(keys_only=True)
    departure_keys = [i for k, i in matching.items() if "departure" in k]
    return product([my_ticket[i] for i in departure_keys])