#Covering for Linear Grammars

def find_linear_grammar_cover(grammar):
    # Initialize an empty set of non-terminals
    non_terminals = set(grammar.keys())

    # Compute the set of strings generated by the grammar
    strings = set()
    for productions in grammar.values():
        for production in productions:
            strings.add(production)

    # Find the minimum set of non-terminals that cover all strings
    while strings:
        max_coverage = set()
        max_string = None

        # Find the string with maximum coverage
        for string in strings:
            coverage = set()
            for non_terminal, productions in grammar.items():
                if string in productions:
                    coverage.add(non_terminal)
            if len(coverage) > len(max_coverage):
                max_coverage = coverage
                max_string = string

        # Remove the string from the set and remove the covering non-terminals
        strings.remove(max_string)
        non_terminals -= max_coverage

    # Return the minimum set of non-terminals that cover all strings
    return non_terminals


# Example usage
grammar = {
    'S': ['aA', 'bB', ''],
    'A': ['aA', 'a'],
    'B': ['bB', 'b']
}

linear_grammar_cover = find_linear_grammar_cover(grammar)
print(f"Linear Grammar Cover: {linear_grammar_cover}")

