Problema C - Torre defeituosa

Este é um problema de interação.
Ao contrário dos outros problemas em que deves fazer leitura de dados e escrita do output, neste problema deves interagir com o avaliador através da implementação de uma função e da interação com as funções fornecidas.

A bonita cidade de Tondela está prestes a ser o centro de uma revolução tecnológica. Está a ser instalada uma enorme rede de torres de comunicação, que irão providenciar wi-fi gratuito de alta velocidade em qualquer zona da cidade!

O sistema é constituído por N torres de comunicação que estão interligadas com cabos de alta velocidade. Há exatamente N - 1 cabos bidirecionais a interligar torres, e cada um liga duas torres distintas. Além disso, sabe-se que o sistema de cabos é conexo, ou seja, é possível chegar de uma torre a uma qualquer outra torre seguindo apenas cabos.

As torres e os cabos estão todos em posição e está tudo pronto para ser lançado, mas aparentemente uma das torres tem um problema de conexão que está a afetar o sistema todo! O maior problema é que ninguém sabe qual é.

Para descobrir onde se encontra a torre defeituosa, os engenheiros do projeto conseguem investigar qualquer uma das torres e descobrir se é essa a torre defeituosa. Além disso, caso a torre não seja a defeituosa, os engenheiros conseguem determinar qual das torres ligadas com cabos à torre analisada está mais próxima da torre defeituosa (em termos de número de cabos que é necessário seguir para a atingir).

O tempo disponível pelos engenheiros não é muito, por isso só conseguem analisar no máximo D torres antes de atingirem o limite de tempo do projeto. Consegues ajudá-los a escolher as torres para analisar de modo a concluírem o projeto a tempo?

O Problema

Dado um conjunto de N torres e os cabos que as ligam, determinar a torre defeituosa em menos de D tentativas.

Ficheiros para Download

Podes começar por descarregar os ficheiros correspondentes à tua linguagem (ou um arquivo zip contendo tudo):

Linguagem Ficheiro a implementar Ficheiro com avaliador exemplo Ficheiros auxiliares Input para avaliador exemplo
C resolver.c avaliador.c avaliador.h input.txt
C++ resolver.cpp avaliador.cpp
Java resolver.java avaliador.java ------
Pascal resolver.pas avaliador.pas avaliadorlib.pas

Nota que a implementação do avaliador a usar nos testes oficiais será diferente, mas podes esperar o mesmo comportamento. Além disso, é garantido que o avaliador demora menos de 0.1 segundos a analisar D torres.

Implementação

Deves submeter um único ficheiro que implementa a função resolver(N, D, Es, Et), que recebe um inteiro N, que representa o número de torres, um inteiro D que representa o número máximo de análises que podem ser efetuadas, e duas listas de torres Es e Et, cada uma com N - 1 elementos onde o i-ésimo elemento da lista Es representa um dos extremos do i-ésimo cabo e o de Et o outro extremo (ou seja, as duas listas representam os N - 1 cabos). Para isso deves usar o ficheiro resolver.{c,cpp,java,pas} que descarregaste, colocando no interior da função o teu código. Podes acrescentar outras funções, mas devem ficar todas neste ficheiro que é o único que deves submeter.

Função a implementar:
C++/C:void resolver(int N, int D, int Es[MAXN], int Et[MAXN]);
Java:void resolver(int N, int D, int[] Es, int[] Et);
Pascal:procedure resolver(N : longint, D : longint, Es : array of longint, Et : array of longint);

A tua função deve invocar a seguinte função:

analisar(V) implementada pelo avaliador, que recebe uma torre V e devolve -1 caso esta seja a torre defeituosa, ou a torre U mais próxima da defeituosa caso contrário.

Nota que é importante que V esteja entre 1 e N. Também é importante notar que se excederes as D análises o programa será interrompido e a resposta será considerada incorreta.

Funções do avaliador:
C/C++/Java:int analisar(int V);
Pascal:function analisar(V : longint) : longint;

O teu objetivo é descobrir a torre defeituosa. Para tal, deves chamar a função analisar(V) com a torre correta, ao qual esta irá retornar -1 e não deverás chamar mais nenhuma vez a função analisar(V).

A vossa função não deve ler nem escrever para os canais de entrada/saída padrão.

Exemplo

Imagina que o sistema tem N = 6 torres, tens D = 5 análises e que há uma ligação entre as seguintes torres: (1, 2), (1, 3), (2, 4), (2, 5), (3, 6). A função resolver que deves implementar será chamada como resolver(6, 5, {1, 1, 2, 2, 3}, {2, 3, 4, 5, 6}).

Uma possível execução seria a seguinte (com a ordem das chamadas a ser de cima para baixo):

InvocaçãoResultadoDescrição
analisar(2)1A torre 2 não é a defeituosa e a 1 é a mais próxima das 3 possíveis (1, 4, 5).
analisar(1)3A torre 1 não é a defeituosa e a 3 é a mais próxima das 2 possíveis (2, 3).
analisar(3)6A torre 3 não é a defeituosa e a 6 é a mais próxima das 2 possíveis (1, 6).
analisar(6)-1É a torre 6!

Para este exemplo, a torre defeituosa era a número 6. A imagem seguinte mostra este exemplo.

Restrições

São garantidos os seguintes limites em todos os casos de teste:
1 ≤ N ≤ 100 000Número de torres.
1 ≤ D ≤ NNúmero de tentativas.

Avaliação e Casos de Teste

Os casos de teste deste problema estarão agrupados em conjuntos de testes. Ao contrário dos restantes problemas, para obter pontuação é necessário acertar todos os casos de teste de um grupo de casos, nesse caso terão a pontuação completa relativa a esse grupo. Se falharem um ou mais casos de um grupo, a pontuação atribuída relativa a esse grupo será nula.

Cada grupo tem um número de pontos associado e um conjunto de restrições adicionais. Os grupos são os seguintes:

Grupo Número de Pontos Restrições adicionais
1 10 N ≤ 100, D = N
2 20 N ≤ 100, D = N / 2
3 20 D = 20, as torres formam uma linha (ver imagem a baixo)
4 25 N ≤ 1 000, D = 12
5 25 D = 20

Testes no vosso computador

É disponibilizado um avaliador exemplo em cada linguagem (avaliador.{c,cpp,java,pas}) que pode ser utilizado para testar a vossa submissão. Para C/C++/Pascal está ainda disponível um ficheiro auxiliar (para C/C++ o avaliador.h e para Pascal o avaliadorlib.pas). Este avaliador não corresponde ao utilizado pelo sistema de avaliação.

Este avaliador começa por receber como input um inteiro N e um inteiro D correspondendo, respetivamente, ao número de torres e ao número máximo de análises. Seguem-se N - 1 linhas, cada uma com 2 inteiros entre 1 e N que representam os extremos de cada cabo. Finalmente, segue-se uma linha com apenas um inteiro que representa o número da torre defeituosa.

O avaliador irá automaticamente invocar a função resolver(N, D, Es, Et) por vocês implementada e indicará se a resposta foi correta. Em caso afirmativo, também indicará o número de análises que foram efetuadas.

Disponibilizamos um ficheiro input.txt que contém o caso de exemplo referido a cima.

Um exemplo de teste na tua máquina (supondo que tens os compiladores oficiais instalados) seria o seguinte:

LinguagemCompilarExecutar com o exemplo
Cgcc -Wall avaliador.c resolver.c./a.out < input.txt
C++g++ -Wall avaliador.cpp resolver.cpp./a.out < input.txt
Javajavac avaliador.java resolver.javajava avaliador < input.txt
Pascalfpc avaliador.pas./avaliador < input.txt

Final Nacional das ONI'2017
Departamento de Ciência de Computadores
Faculdade de Ciências da Universidade do Porto
(8 de Maio de 2017)