Aula 10: Tratabilidade

Documentos relacionados
Uma forma de classificação

Teoria da Computação. Complexidade computacional classes de problemas

ACH2043 INTRODUÇÃO À TEORIA DA COMPUTAÇÃO. Aula 25

Projeto e Análise de Algoritmos NP Completude. Prof. Humberto Brandão

Máquinas de Turing 3

Melhores momentos AULA PASSADA. Complexidade Computacional p. 205

Teoria da Computação. Computabilidade e complexidade computacional

Complexidade de Algoritmos. Edson Prestes

Aula 9: Máquinas de Turing

Problemas Intratáveis ou computação eficiente X computação ineficiente

Introdução à Teoria da Computação Exercícios

Complexidade de Algoritmos

Aula 10: Decidibilidade

5COP096 TeoriadaComputação

Complexidade computacional

Técnicas de Extensão de MT

Problemas de otimização

Árvore Geradora Mínima

PCC104 - Projeto e Análise de Algoritmos

INTRATABILIDADE e NP-COMPLETUDE

Complexidade computacional

Complexidade de Tempo

Complexidade de Algoritmos. Edson Prestes

Teoria da Complexidade Computacional

Algoritmos em Grafos COM11087-Tópicos Especiais em Programação I

TEORIA DE COMPLEXIDADE

Capítulo 9: Linguagens sensíveis ao contexto e autômatos linearmente limitados.

Capítulo 8: O problema da parada. Decidibilidade e computabilidade. José Lucas Rangel Introdução.

Teoria da Complexidade Computacional

ACH2043 INTRODUÇÃO À TEORIA DA COMPUTAÇÃO. Aula 18. Cap O Problema da Parada

Algoritmos de Aproximação Segundo Semestre de 2012

Modelos de Computação Folha de trabalho n. 10

Aula 10: Decidibilidade

Análise e Síntese de Algoritmos. Problemas NP-Completos CLRS, Cap. 34

Melhores momentos AULA PASSADA. Complexidade Computacional p. 136

Árvores Árvores Geradoras de Custo Mínimo 0/16

Universidade Federal de Alfenas

GRAFOS. Prof. André Backes. Como representar um conjunto de objetos e as suas relações?

Preliminares. Profa. Sheila Morais de Almeida. agosto

Projeto e Análise de Algoritmos NP Completude Parte 2. Prof. Humberto Brandão

Máquinas de Turing 3

Como saber se um problema está em NP e não está em P?

Problemas de Busca (a.k.a NP) - parte 2

Uma introdução à complexidade parametrizada

Prova Didática Grafos: Árvores Geradoras e Caminhos Mínimos, Análise de Complexidade

Linguagem Universal. assim como a entrada ser processada por a. (b) A segunda fita de representa a fita de

Análise e Síntese de Algoritmos

Grafos: Busca. Algoritmos e Estruturas de Dados 2. Graça Nunes

Linguagens recursivamente enumeráveis

Medida do Tempo de Execução de um Programa. David Menotti Algoritmos e Estruturas de Dados II DInf UFPR

Redutibilidade. Mário S. Alvim Fundamentos de Teoria da Computação (FTC) DCC-UFMG (2018/02)

Algoritmos Combinatórios: Introdução

Algoritmo. Exemplo. Definição. Programação de Computadores Comparando Algoritmos. Alan de Freitas

Modelos Universais de Computação

Análise e Projeto de Algoritmos

Teoria da Computação. Computabilidade e complexidade computacional

ANÁLISE DE COMPLEXIDADE DOS ALGORITMOS

Problemas Computáveis

Grafos: árvores geradoras mínimas. Graça Nunes

Capítulo 2: Procedimentos e algoritmos

3. Resolução de problemas por meio de busca

GRAFOS Aula 08 Árvore Geradora Mínima: Algoritmos de Kruskal e Prim-Jarnik Max Pereira

Matemática Discreta. Aula 06: Teoria dos Grafos. Tópico 01: Grafos e suas Representações. Observação

Projeto e Análise de Algoritmos

Teoria dos Grafos Aula 2

Aula 3: Autômatos Finitos

Computabilidade e Complexidade (ENG10014)

Grafos Árvores Geradoras Mínimas

Otimização em Grafos

PROGRAMAÇÃO E ALGORITMOS (LEII) Universidade da Beira Interior, Departamento de Informática Hugo Pedro Proença, 2016/2017

Complexidade de Algoritmos

Algoritmo Aproximação. Prof. Anderson Almeida Ferreira [DPV]9.2 [ZIV]9.2.2 e 9.2.3

Projeto e Análise de Algoritmos

TEORIA DE COMPLEXIDADE

ANÁLISE DE ALGORITMOS (INF 1721)

Turing e Complexidade

Análise e Complexidade de Algoritmos

Faculdade de Computação

Prof. Marco Antonio M. Carvalho

Definição 1.1 : Uma árvore é um grafo simples conexo e sem ciclos.

Aula 3: Autômatos Finitos

Capítulo 2- Modelos de grafos.

Marcos Castilho. DInf/UFPR. 16 de maio de 2019

5COP096 TeoriadaComputação

Complexidade de Algoritmos

CI065 CI755 Algoritmos e Teoria dos Grafos

Complexidade de Tempo e Espaço

Teoria da computabilidade Indecidíveis Decidíveis

Algoritmos Genéticos

UNIVERSIDADE FEDERAL DO RIO DE JANEIRO DEPARTAMENTO DE CIÊNCIAS DA COMPUTAÇÃO. 5 a Lista de Exercícios

Polinomial: função de complexidade é O(p(n)), onde p(n) é um polinômio.

Introdução Maquinas de Turing universais O problema da parada. Indecidibilidade. Rodrigo Gabriel Ferreira Soares DEINFO - UFRPE.

Noções da Teoria dos Grafos. André Arbex Hallack

Juliana Kaizer Vizzotto. Universidade Federal de Santa Maria. Disciplina de Teoria da Computação

Medida do Tempo de Execução de um Programa

Projeto e Análise de Algoritmos

Análise de Algoritmos

Teoria dos Grafos. Edson Prestes

Matemática Aplicada às Ciências Sociais- 11º ano (Versão: para o manual a partir de 2016/17)

1. Uma linguagem de uma máquina de Turing

Transcrição:

Teoria da Computação DAINF-UTFPR Aula 10: Tratabilidade Prof. Ricardo Dutra da Silva Na aula anterior discutimos problemas que podem e que não podem ser computados. Nesta aula vamos considerar apenas problemas que podem ser computados e nosso interesse é saber quão rápido a computação é realizada. Trataremos, portanto, de problemas decidíveis que podem ser computados de forma eficiente e problemas decidíveis que não podem ser computados de forma eficiente. Nossa definição de tempo para execução de um algoritmo será considerada em termos de passo realizados por uma Máquina de Turing. Definição 10.1. O tempo de processamento de uma Máquina de Turing M sobre uma string w é o número de passos realizados pela máquina antes de parar. Se a máquina não parar, o tempo de processamento é infinito. Definição 10.2. A complexidade de tempo de uma Máquina de Turing M é a função t(n) cujo valor é o tempo de processamento máximo sobre todas as entradas de tamanho n. Exemplo 10.1 Considere a Máquina de Turing para a linguagem L = {0 i 1 i i 1}. Para decidir L a máquina pode fazer as seguintes operações: 1. Percorre a fita e se um 0 é encontrado à direita de um 1 a máquina pára em um estado não final. 2. Iterativamente corta um único 0 e um único 1. Se sobrar algum 0 ou 1 não cortado, a máquina pára em um estado não final. Caso contrário, a máquina pára em um estado final. Dada uma string w de entrada com tamanho w = n, no passo 1, a máquina percorre no máximo todos os elementos de w. São realizadas n operações no máximo. O passo dois realiza no máximo n operações para cada iteração. Cada iteração corta dois elementos, um 0 e um 1. Portanto, são realizadas n n2 iterações que contabilizam 2 2 operações. A complexidade da máquina é então no máximo t(n) = n + n2 2, ou seja, O(n2 ). A linha divisória de eficiência é basicamente estabelecida entre algoritmos que podem ser computados em tempo polinomial e algoritmos que exigem tempo exponencial. Problemas 1

2 Aula 10: Tratabilidade que não possuem um algoritmo polinomial são chamados intratáveis enquanto aqueles que possuem são chamados tratáveis. Porque a divisão entre tempos polinomial e exponencial? Como um exemplo prático, considere funções como n 3 e 2 n, que surgem com frequência para descrever a complexidade de tempo para algoritmos. Para uma entrada de tamanho razoável, como n = 1000, temos n 3 igual a um bilhão. Ou seja, uma máquina com complexidade n 3 realizaria um bilhão de passos antes de parar. Uma máquina com complexidade exponencial realizaria 2 1000 operações. Para ter uma ideia do que esse número significa, o número máximo de átomos no universo é estimado em algo próximo a 2 272. Algoritmos exponenciais são raramente úteis, uma vez que para entradas comuns esses algoritmos podem levar um tempo computacional que possivelmente o universo não gostaria de esperar. Definição 10.3. Seja T : N R +. A classe de complexidade de tempo T IME(t(n)) é definida como o conjunto de todas as linguagens que são decidíveis por uma Máquina de Turing com tempo de processamento O(t(n)). A linguagem do Exemplo 10.1 pertence à classe de complexidade T IME(n 2 ). No entanto, é possível obter algoritmos assintoticamente melhores que O(n 2 ) para a linguagem. Em uma Máquina de Turing com uma fita é possível obter uma algoritmo O(n log n) e numa máquina com duas fitas é possível obter um algoritmo O(n). Esses resultados dependem do modelo usado. No entanto, o modelo não afeta tanto assim a complexidade. A diferença é polinomial e estamos interessados em classificar problemas em polinomiais e exponenciais, tratáveis ou intratáveis. Vamos definir a primeira classe de problemas que nos interessa. Definição 10.4. P é o conjunto de linguagens que são decidíveis em tempo polinomial em uma Máquina de Turing determinística com uma fita. P = k T IME(n k ). Exemplo 10.2 Uma árvore geradora é um subconjunto de arestas sem ciclos que conectam todos os nodos de um grafo. Uma árvore geradora mínima é uma árvore geradora com o menor total de peso de arestas entre todas as árvores geradoras. O algoritmo de Kruskal computa uma árvore geradora mínima da seguinte forma: 1. Cada nodo do grafo é mantido em uma estrutura de componente conexa. Inicialmente nenhuma aresta é selecionada e cada nodo forma uma componente conexa.

Aula 10: Tratabilidade 3 2. A cada iteração, a aresta de menor custo é recuperada. Se a aresta une nodos em componentes conexas diferentes, seleciona a aresta para a árvore geradora e une as componentes conexas dos dois nodos Considere o grafo abaixo. 15 1 2 10 12 20 3 4 18 Inicialmente é escolhida a aresta (1,3). Depois a aresta (2,3). A aresta (1,2) é testada na sequência, mas não é escolhida pois formaria um ciclo. A aresta (3,4) é então escolhida. A última aresta testada é a (2,4), mas esta também forma ciclo. Neste momento temos a árvore geradora mínima mostrada abaixo. Com uma estrutura union-find o algoritmo pode ser implementado em tempo O( V + E log E ). 1 2 10 12 3 4 18 Vamos desenvolver um algoritmo mais simples que pode ser implementado em uma Máquina de Turing. Manteremos uma estrutura do tipo vetor com tamanho V em que cada posição, relacionada com um vértice específico, vai armazenar a componente conexa de um vértice. O algoritmo computa os passos a seguir. 1. A aresta de menor custo é encontrada em tempo O( E ) percorrendo todas as arestas. 2. As componentes conexas dos vértices da aresta de menor custo são descobertas percorrendo o vetor auxiliar em tempo O( V ). 3. Se as componentes são diferentes, todos os vértices que estão na mesma componente são marcados para a componente de um dos vértices. Isso pode é feito em O( V ).

4 Aula 10: Tratabilidade Fazendo o processo para todas as arestas obtemos um tempo total de O( E ( E + V )) que é polinomial. Quando usamos MT s é mais fácil tratar problemas como linguagens, como problemas de decisão. O problema de decisão para árvores geradoras mínimas pode ser pensado como: Dado um grafo G e um peso W, existe uma árvore geradora mínima de peso W em G?. Este problema parece mais fácil que o problema de achar uma resposta. Mas estamos interessados em saber o quão difícil é um problema. Neste caso, se o problema da linguagem for difícil, o problema de encontrar a resposta será tão ou mais difícil. A linguagem do problema das árvores geradoras mínimas é P agm = {(G, W ) G é um grafo com uma árvore geradora mínima de custo máximo W }. Se W 40, o grafo do exemplo anterior pertence à linguagem. Outra consideração importante é quanto ao tamanho da entrada (da string) na MT. Pensamos em tamanhos de grafos como o número de vértices mais o número de arestas. Em uma MT o grafo de entrada dever ser codificado como uma string. Essa representação não pode ser bem maior do que um fator polinomial. Se a codificação transformasse um grafo numa string com tamanho exponencialmente maior do que o número de vértices e arestas, o tempo de computação polinomial já seria violado. Felizmente, em geral, é possível obter uma codificação cujo tamanho não é maior do que um fator polinomial. Quando usamos uma codificação binária, seu tamanho até aproxima-se mais do que seria a codificação real em bits usada por um computador. Exemplo 10.3 Poderíamos representar o grafo para o problema da árvore mínima geradora da seguinte forma. 1. Os vértices são numerados de 1 a V. 2. O código inicia com o valor binário de V separado por vírgula do peso W em binário. 3. Para cada aresta existente (i, j), codificamos como (enc(i), enc(j), enc(w)), onde a função enc(.) codifica o valor binário respectivo para os vértices e peso. Para o grafo de exemplo, com limite W = 40, teríamos a codificação: 100, 101000(1, 10, 1111)(1, 11, 1010)(10, 11, 1100)(10, 100, 10100)(11, 100, 10010).

Aula 10: Tratabilidade 5 Vimos que a classe P é formada por linguagens para as quais existe um algoritmo de tempo polinomial que as aceite. No entanto, existem linguagens para as quais não são conhecidos algoritmos de tempo polinomial. Vamos analisar o problema do Caixeiro Viajante. A entrada para este problema é um grafo, com pesos nas arestas, e um valor limite de custo W. A pergunta do problema é: Existe um Ciclo Hamiltoniano de peso máximo W em G?. Um Ciclo Hamiltoniano é uma sequência de arestas que conectam todos os vértices sem repetir vértices. Em geral, pensamos no problema como um vendedor que precisa visitar um conjunto de cidades percorrendo estradas que as conectam sem repetir cidades, a não ser a primeira que deve ser também a última. A linguagem do problema é então P cv = {(G, W ) G é um grafo com um ciclo hamiltoniano de custo máximo W }. Exemplo 10.4 O grafo da figura abaixo possui um ciclo hamiltoniano, dado pela sequência de vértices 1, 2, 4, 3, 1. O peso total deste ciclo é 63. Se W 63, a resposta para a pergunta do problema é sim. 15 1 2 10 12 20 3 4 18 Por força bruta é possível descrever um algoritmo muito simples para o problema. Basta testa todas as permutações dos vértices de um grafo. Para cada permutação testamos se existem vértices repetidos que não sejam os finais. Isso leva tempo O( V ). Como existem O( V!) permutações, o algoritmo computa aproximadamente V! vezes V operações, ou seja, tem complexidade O( V!). Isso é ainda pior do que tempo exponencial. É possível escrever algoritmos mais espertos, que evitem certas operações. No entanto, parece que não importa o que fizermos, um número exponencial de ciclos ainda precisa ser verificado antes de concluir se existe ou não um Ciclo Hamiltoniano. Ninguém conseguiu produzir um algoritmo com tempo menor do que exponencial (no pior caso). Mesmo que não seja conhecido um algoritmo polinomial para o problema do Caixeiro

6 Aula 10: Tratabilidade Viajante, o problema apresenta uma propriedade importante para entender sua complexidade: é possível verificar que existe um Ciclo Hamiltoniano se ele for descoberto, ou seja, de alguma forma o ciclo é dado. Definição 10.5. Um verificador para uma linguagem L é um algoritmo V tal que L = {w V aceita (w, c) para alguma string c}. O tempo de V é medido em termos do tamanho de w. Portanto, um verificador de tempo polinomial executa em tempo polinomial no tamanho de w. Uma linguagem é polinomialmente verificável se ela tem um verificador de tempo polinomial. A string c do verificador é uma informação adicional para verificar que uma string w pertence a L. Essa informação é chamada de certificado de que w pertence a L. Para verificadores polinomiais, o certificado necessariamente tem que ter tamanha polinomial em relação ao tamanho de w. Caso tivesse tamanho exponencial o verificador não seria mais polinomial porque o verificador neste caso seria limitado pelo tempo de acesso (leitura, processamento) ao certificado. Exemplo 10.5 Para o problema do Caixeiro Viajante, o certificado para uma string (G, W ) seria um ciclo hamiltoniano em G. Para verificar o certificado basta percorrê-lo e realizar as seguintes operações: 1. Para todo vértice do certificado marca o vértice correspondente do grafo. 2. Verifica se existem as arestas entre dois vértices subsequentes do certificado. 3. Verifica se o custo total das arestas é no máximo W. 4. Se todos os vértices foram marcados no passo 1 e existem as arestas verificadas no passo 2, então o certificado é um Ciclo Hamiltoniano. Todos os passo podem ser feitos em O( V ). Logo o verificador tem tempo polinomial. Definição 10.6. tempo polinomial. A classe N P é formada por linguagens que possuem um verificador de O nome N P vem de uma definição alternativa para essa classe de problemas. Definição 10.7. Uma linguagem L pertence à classe N P (polinomial não-determinística), se existe uma Máquina de Turing Não-Determinística M e uma complexidade de tempo

Aula 10: Tratabilidade 7 polinomial t(n) tal que L = L(M) e com uma entrada de tamanho n não existem caminhos com mais de t(n) operações em M. Exemplo 10.6 Uma NTM que decide o problema do caixeiro viajante em tempo polinomial: 1. Escolhe uma lista de números p 1, p 2,.., p m, p 1 onde cada uma dos números é um nodo de G. 2. Checa por repetições nos nodos p 2,..., p m. Se achar rejeita. 3. Checa se o custo é menor que W. Se não for rejeita. 4. Checa se cada par de nodos subsequentes formam uma aresta em G. Se não formar rejeita. 5. Se passou em tudo responde sim. A máquina não-determinística consegue escolher todas as possíveis listas de vértices no passo 1 e executá-las em paralelo. Cada um dos ramos executados leva tempo polinomial pois todas as etapas do algoritmo fazem no máximo um número polinomial de operações. Definição 10.8. Seja T : N R +. A classe de complexidade de tempo NT IME(t(n)) é definida como o conjunto de todas as linguagens que são decidíveis por uma NTM com tempo de processamento O(t(n)). Definição 10.9. N P é o conjunto de linguagens que são decidíveis em tempo polinomial em uma máquina de Turing Não-Determinística, N P = k NT IME(n k ). Exemplo 10.7 Uma clique de um grafo é um subgrafo que tem todos os vértices conectados por uma aresta. Uma k-clique é uma clique que contém k vértices. O grafo do exemplo abaixo possui uma 5-clique.

8 Aula 10: Tratabilidade 1 2 3 7 4 5 6 O problema da clique consiste em encontrar, em um grafo G, uma clique de tamanho k P C = {(G, k) G contém uma k-clique } O problema da clique pertence a N P e podemos verificar isso usando uma clique c como certificado e construindo o verificador V com entrada ((G, k), c): 1. Testa se c é um conjunto de k nós em G; 2. Testa se G contém todas as arestas conectando nós em c. 3. Se ambos os testes são verdadeiros responde sim, senão responde não. Ou podemos provar por uma MT não-determinística M: 1. Seleciona não-deterministicamente um subconjunto de k nodos em G como c. 2. Testa se G contém todas as arestas conectando nós em c. 3. Se aceita responde sim, se não aceita responde não. Agora sabemos que P contém os problemas que podem ser testados em tempo polinomial enquanto N P contém os problemas que podem ser verificados em tempo polinomial. Uma MT determinística é um MT não-determinística que não tem escolha de movimentos, portanto a classe P N P. No entanto, não sabemos se tudo o que pode ser feito em tempo polinomial por um MT não-determinística pode também ser feito por uma MT determinística em tempo polinomial. Essa é a grande questão da Teoria da Computação: P = N P?.