{}
run-icon
main.py
# ATIVIDADE 01 PARA NOTA P2 # Matemática Discreta com Python # Aluno: Samuel Ribeiro # ============================================================ # FUNÇÃO AUXILIAR - PROTEÇÃO CONTRA ENTRADAS INVÁLIDAS # ============================================================ # Criei essa função para proteger todas as entradas numéricas do programa. # Se eu usasse int(input()) diretamente, o programa quebraria com um # erro fatal (ValueError) caso alguém (vulgo Cristiane) digitasse uma letra # ou apertasse enter sem digitar nada. Com o try/except, o erro é capturado # e o programa simplesmente avisa e pede de novo, dentro de um loop # while True, até receber um número inteiro válido de verdade. def obter_inteiro(mensagem): while True: try: return int(input(mensagem)) except ValueError: print("Entrada invalida! Por favor, digite um numero inteiro.") except EOFError: print("\nEntrada encerrada.") return None # ============================================================ # EXERCÍCIO 1 - OPERAÇÕES E PROPRIEDADES DE CONJUNTOS # ============================================================ def exercicio_1(): print("\n--- Exercicio 1: Operacoes e Propriedades de Conjuntos ---") # Optei por ler os elementos como um único texto, pedindo ao usuário # que separe por vírgula. É mais prático do que perguntar elemento # por elemento em um loop interativo. # Captura EOFError caso o stdin acabe (comportamento do OneCompiler). try: entrada_a = input("Informe os elementos do conjunto A (separados por virgula): ") entrada_b = input("Informe os elementos do conjunto B (separados por virgula): ") except EOFError: print("\nEntrada encerrada.") return # Trocamos as vírgulas por espaços vazios e usamos o split() vazio. # O split() nativo corta o texto considerando qualquer bloco de espaços, # o que resolve o problema caso a pessoa digite "1 2 3" ao inves de "1, 2, 3". # A condicao 'elem not in A' garante que nao havera duplicatas, respeitando # a definicao matematica de conjunto (sem elementos repetidos). A = [] for elem in entrada_a.replace(',', ' ').split(): if elem not in A: A.append(elem) B = [] for elem in entrada_b.replace(',', ' ').split(): if elem not in B: B.append(elem) print("\n[Passo 2] Conjuntos informados:") print(f"Conjunto A: {A}") print(f"Conjunto B: {B}") # UNIÃO (A U B): # Copiei todos os elementos de A de uma vez com list(A) e depois # varri o conjunto B. Para cada elemento de B, só adiciono na # união se ele ainda não estiver lá, evitando repetições. uniao = list(A) print("\n[Passo 3.1] Calculando Uniao A U B...") for elem in B: if elem not in uniao: print(f"Adicionando '{elem}' do conjunto B a uniao.") uniao.append(elem) print(f"Resultado A U B: {uniao}") # INTERSEÇÃO (A ∩ B): # Percorri o conjunto A elemento por elemento. Se aquele elemento # também existir dentro de B, então ele é comum aos dois conjuntos # e pertence à interseção. Fui adicionando cada um na lista. intersecao = [] print("\n[Passo 3.2] Calculando Intersecao A n B...") for elem in A: if elem in B: print(f"O elemento '{elem}' esta em ambos os conjuntos.") intersecao.append(elem) print(f"Resultado A n B: {intersecao}") # DIFERENÇA (A - B): # Tudo que tem em A e não tem em B. Varro A e salvo apenas # o que não está contido em B. diferenca_a_b = [] print("\n[Passo 3.3] Calculando Diferenca A - B...") for elem in A: if elem not in B: diferenca_a_b.append(elem) else: print(f"O elemento '{elem}' foi removido de A pois pertence a B.") print(f"Resultado A - B: {diferenca_a_b}") # DIFERENÇA (B - A): # O mesmo raciocínio de forma invertida: varro B e salvo # apenas o que não está contido em A. diferenca_b_a = [] print("\n[Passo 3.4] Calculando Diferenca B - A...") for elem in B: if elem not in A: diferenca_b_a.append(elem) else: print(f"O elemento '{elem}' foi removido de B pois pertence a A.") print(f"Resultado B - A: {diferenca_b_a}") # PRODUTO CARTESIANO (A x B): # O produto cartesiano exige combinar cada elemento de A com todos # os de B. Usei dois laços for aninhados: o externo percorre A e # o interno percorre B. Em cada combinação formo um par ordenado # (a, b) e guardo na lista. produto_cartesiano = [] print("\n[Passo 4] Calculando Produto Cartesiano A x B...") for a in A: for b in B: print(f"Formando par: ({a}, {b})") produto_cartesiano.append((a, b)) print(f"Resultado A x B: {produto_cartesiano}") # SUBCONJUNTO (A contido em B): # Parti do princípio que é verdade (a_contido_b = True). # Se achar qualquer elemento de A que não está em B, mudo para # False e dou break para parar a busca, poupando processamento. print("\n[Passo 5] Verificando subconjuntos...") a_contido_b = True for elem in A: if elem not in B: a_contido_b = False print(f"Elemento '{elem}' de A nao esta em B. Logo, A nao e subconjunto de B.") break if a_contido_b: print("Todos os elementos de A estao em B. Logo, A e subconjunto de B (A c B).") # SUBCONJUNTO (B contido em A): mesmo raciocínio, direção inversa. b_contido_a = True for elem in B: if elem not in A: b_contido_a = False print(f"Elemento '{elem}' de B nao esta em A. Logo, B nao e subconjunto de A.") break if b_contido_a: print("Todos os elementos de B estao em A. Logo, B e subconjunto de A (B c A).") # CARDINALIDADE: # Usei len() para contar o número de elementos de cada conjunto. # A cardinalidade é simplesmente o tamanho da lista. print("\n[Passo 6] Cardinalidades:") print(f"|A| (Cardinalidade de A): {len(A)}") print(f"|B| (Cardinalidade de B): {len(B)}") print(f"|A U B| (Cardinalidade da Uniao): {len(uniao)}") print(f"|A n B| (Cardinalidade da Intersecao): {len(intersecao)}") # ============================================================ # EXERCÍCIO 2 - MDC, MMC, DIV E MOD # ============================================================ def exercicio_2(): print("\n--- Exercicio 2: MDC, MMC, DIV e MOD ---") # Usei obter_inteiro para garantir que so numeros inteiros sejam aceitos. num1 = obter_inteiro("Informe o primeiro numero inteiro positivo: ") num2 = obter_inteiro("Informe o segundo numero inteiro positivo: ") # Se o EOF aconteceu (stdin esgotado no OneCompiler), encerra o exercicio. if num1 is None or num2 is None: return # Trava de seguranca: o MDC e definido para inteiros positivos. # Alem disso, evita o erro fatal ZeroDivisionError que aconteceria # se num2 fosse 0 nas operacoes de divisao logo abaixo. if num1 <= 0 or num2 <= 0: print("Os numeros devem ser positivos!") return # DIV e MOD: # O operador // já faz a divisão inteira retornando o quociente # sem casas decimais. O operador % retorna o resto da divisão. # São operadores nativos do Python, sem precisar de nenhuma função extra. print("\n[Passo 2.1] Calculando Divisao Inteira (DIV) e Resto (MOD)...") div_inteira = num1 // num2 resto = num1 % num2 print(f"Calculo: {num1} dividido por {num2}") print(f"Divisao inteira (DIV): {num1} // {num2} = {div_inteira}") print(f"Resto da divisao (MOD): {num1} % {num2} = {resto}") # MDC - ALGORITMO DE EUCLIDES: # Implementei o algoritmo manualmente com um while. A lógica é: # enquanto o segundo número não for zero, calculo o resto da divisão # do primeiro pelo segundo. Depois, o primeiro vira o segundo e o # segundo vira esse resto. Quando o segundo chegar a zero, o MDC # é o valor que sobrou no primeiro. Imprimo cada passo para mostrar # o raciocínio completo. print("\n[Passo 2.2] Calculando MDC pelo Algoritmo de Euclides...") a = num1 b = num2 while b != 0: novo_resto = a % b print(f"Dividindo {a} por {b} -> Resto = {novo_resto}") a = b b = novo_resto mdc = a print(f"O MDC({num1}, {num2}) e {mdc}") # MMC A PARTIR DO MDC: # Usei a propriedade matemática: o produto de dois números é igual # ao produto do MDC pelo MMC. Isolando o MMC: MMC = (A * B) / MDC. # Usei // para manter como inteiro, pois essa divisão é sempre exata. print("\n[Passo 2.3] Calculando MMC a partir do MDC...") mmc = (num1 * num2) // mdc print(f"Formula: ({num1} * {num2}) / {mdc}") print(f"O MMC({num1}, {num2}) e {mmc}") # ============================================================ # EXERCÍCIO 3 - ARITMÉTICA MODULAR, CONGRUÊNCIA E INVERSO EM Zn # ============================================================ def exercicio_3(): print("\n--- Exercicio 3: Aritmetica Modular, Congruencia e Inverso em Zn ---") n = obter_inteiro("Informe o valor de n (para o conjunto Zn): ") if n is None: return if n <= 0: print("O valor de n deve ser maior que 0.") return # Usei list(range(n)) para criar o conjunto Zn. # O range(n) gera os números de 0 até n-1 automaticamente, # que é exatamente a definição de Zn = {0, 1, ..., n-1}. Zn = list(range(n)) print(f"Conjunto Z_{n} = {Zn}") # TABELA DE ADIÇÃO MODULAR: # Usei dois laços for aninhados: o externo para as linhas (i) # e o interno para as colunas (j). O cálculo (i+j)%n garante que # o resultado sempre fique dentro de Zn. As f-strings com :2 # forçam cada número a ocupar 2 caracteres, deixando a tabela alinhada. print(f"\n[Passo 2.1] Tabela de Adicao Modular em Z_{n}:") print(" + | " + " ".join(f"{x:2}" for x in Zn)) print("-" * (5 + 4 * n)) for i in Zn: linha = f"{i:2} | " for j in Zn: resultado = (i + j) % n linha += f"{resultado:2} " print(linha) # TABELA DE MULTIPLICAÇÃO MODULAR: # Mesma lógica da adição, mas o cálculo é (i*j)%n. print(f"\n[Passo 2.2] Tabela de Multiplicacao Modular em Z_{n}:") print(" * | " + " ".join(f"{x:2}" for x in Zn)) print("-" * (5 + 4 * n)) for i in Zn: linha = f"{i:2} | " for j in Zn: resultado = (i * j) % n linha += f"{resultado:2} " print(linha) # CONGRUÊNCIA MODULAR: # Calculei a%n e b%n separadamente. Dois números são congruentes # módulo n quando deixam o mesmo resto ao ser divididos por n. # Então basta comparar se mod_a == mod_b. print("\n[Passo 3 e 4] Verificacao de Congruencia") a = obter_inteiro("Informe um numero inteiro a: ") b = obter_inteiro("Informe um numero inteiro b: ") if a is None or b is None: return mod_a = a % n mod_b = b % n print(f"Calculando {a} mod {n} = {mod_a}") print(f"Calculando {b} mod {n} = {mod_b}") if mod_a == mod_b: print(f"Como os restos sao iguais ({mod_a} == {mod_b}), {a} e congruente a {b} (mod {n}).") else: print(f"Como os restos sao diferentes ({mod_a} != {mod_b}), {a} NAO e congruente a {b} (mod {n}).") # INVERSO MULTIPLICATIVO (DESAFIO EXTRA): # O inverso de x em Zn é um número y tal que (x * y) mod n = 1. # Para encontrar, fiz uma busca percorrendo todos os elementos de Zn. # O primeiro y que der resultado 1 é o inverso. Guardo ele e saio # do loop com break. Se varrer o Zn inteiro sem encontrar, o elemento # não possui inverso multiplicativo. print("\n[Desafio Extra]") x = obter_inteiro(f"Informe um elemento x pertencente a Z_{n} (entre 0 e {n-1}): ") if x is None: return if x < 0 or x >= n: print(f"O elemento {x} nao pertence a Z_{n}.") return print(f"Buscando o inverso multiplicativo de {x} em Z_{n}...") inverso = None for y in Zn: produto = (x * y) % n print(f"Testando {y}: ({x} * {y}) mod {n} = {produto}") if produto == 1: inverso = y break if inverso is not None: print(f"-> O inverso multiplicativo de {x} em Z_{n} e {inverso}, pois ({x} * {inverso}) mod {n} = 1.") else: print(f"-> O elemento {x} NAO possui inverso multiplicativo em Z_{n}.") # ============================================================ # FUNÇÃO PRINCIPAL - MENU DO PROGRAMA # ============================================================ # Criei o main com um while True para manter o menu ativo. # O usuário escolhe qual exercício rodar digitando 1, 2 ou 3, # ou digita 0 para encerrar. Qualquer outra entrada avisa # que é inválida e repete o menu. def main(): print("=" * 50) print("BEM-VINDO A LISTA DE EXERCICIOS DE MATEMATICA DISCRETA") print("=" * 50) while True: print("\nSelecione uma opcao:") print("1 - Exercicio 1 (Conjuntos)") print("2 - Exercicio 2 (MDC, MMC, DIV, MOD)") print("3 - Exercicio 3 (Aritmetica Modular, Congruencia, Inverso)") print("0 - Sair") # Captura EOFError caso o stdin acabe (comportamento do OneCompiler). try: opcao = input("\nDigite sua opcao (ou '0' para sair): ") except EOFError: print("\nPrograma encerrado.") break if opcao == '1': exercicio_1() elif opcao == '2': exercicio_2() elif opcao == '3': exercicio_3() elif opcao == '0': print("Encerrando o programa...") break else: print("Opcao invalida! Tente novamente.") if __name__ == "__main__": main()
Output