1062 - Trilhos

Um dos problemas mais criativos com pilha que eu já vi na vida, um dos meus problemas favoritos desse site.

Descrição

Solução

Para este problema, precisaremos do auxílio de três pilhas diferentes:

  • Uma pilha representando a direção A

  • Uma pilha representando a estação

  • Uma pilha representando a direção B

A pilha da direção A vai começar com os valores na ordem em que estão sendo lidos, ou seja, na ordem que os vagões vão vir. Perceba que se você for colocando os elementos na ordem que o enunciado pede, então a pilha da direção A vai representar corretamente os vagões vindo, ou seja, os vagões virão de trás para frente.

A pilha da estação vai ser utilizada caso nós não consigamos passar o vagão direto da direção A para a direção B, então ela começa vazia.

A pilha da direção B vai começar com os valores na ordem em que desejamos que os vagões saiam, ou seja, na ordem inversa: primeiro saindo o vagão N, depois o N - 1, e assim por diante até o 1. Podemos fazer isso colocando os números de 1 a N na pilha de forma a representar a ordem desejada dos vagões corretamente.

Com essas três pilhas arrumadas, vamos então seguir o seguinte algoritmo:

  • Se os topos das pilhas A e B são iguais, retirar os elementos de ambas as pilhas

    • Neste caso, temos um vagão que está na direção A que pode ir direto para a direção B

  • Se os topos das pilhas da estação e B são iguais, retirar os elementos de ambas as pilhas

    • Neste caso, temos um vagão na estação que pode ir para a direção B

  • Se os dois casos acima não acontecerem, então não tem como o vagão atual nem da direção A nem da estação irem para direção B. Neste caso, precisamos levar o vagão da direção A para a estação.

Se tudo der certo, vamos repetir esses passos até que todas as pilhas se esvaziem, caso em que é possível arrumar os vagões de forma a produzir a ordem desejada na direção B. Porém, pode acontecer duas coisas:

  • Não tem vagão na pilha A e o topo da pilha da estação é diferente do topo da pilha B

  • Não tem vagão nem na pilha A nem na pilha da estação, mas ainda tem vagão na pilha B

Estes dois casos são casos onde é impossível organizar os vagões na ordem pedida.

#include <stdlib.h>
#include <stdio.h>

struct pilhaNo{
    int valor;
    struct pilhaNo* abaixo;
};

struct pilha{
    int tamanho;
    struct pilhaNo* topo;
};

void push(struct pilha* p, int valor){
    p->tamanho += 1;
    struct pilhaNo* novoTopo = (struct pilhaNo*) malloc(sizeof(struct pilhaNo));

    novoTopo->valor = valor;
    novoTopo->abaixo = p->topo;
    p->topo = novoTopo;
}

void pop(struct pilha* p){
    if(p->tamanho > 0){
        p->tamanho -= 1;
        struct pilhaNo* velhoTopo = p->topo;
        p->topo = p->topo->abaixo;
        free(velhoTopo);
    }
}

int top(struct pilha* p){
    return p->topo->valor;
}

int size(struct pilha* p){
    return p->tamanho;
}

int empty(struct pilha* p){
    return p->tamanho == 0;
}

void inicializa(struct pilha* p){
    p->tamanho = 0;
    p->topo = NULL;
}

void destroi(struct pilha* p){
    while(!empty(p)){
        pop(p);
    }
}

int main(){
    int N, x;
    struct pilha A, estacao, B;

    while(scanf("%d", &N) != EOF){
        if(!N)  break;

        while(scanf("%d", &x)){
            if(!x){
                printf("\n");
                break;
            }

            inicializa(&A);
            inicializa(&estacao);
            inicializa(&B);

            push(&A, x);
            push(&B, 1);
            for(int i = 2; i <= N; ++i){
                scanf("%d", &x);
                push(&A, x);
                push(&B, i);
            }

            while(!empty(&A) || !empty(&estacao) || !empty(&B)){
                if(!empty(&A) && !empty(&B) && top(&A) == top(&B)){
                    pop(&A);
                    pop(&B);
                }else if(!empty(&estacao) && !empty(&B) && top(&estacao) == top(&B)){
                    pop(&estacao);
                    pop(&B);
                }else if(!empty(&A)){
                    push(&estacao, top(&A));
                    pop(&A);
                }else{
                    break;
                }
            }

            if(empty(&A) && empty(&estacao) && empty(&B)){
                printf("Yes\n");
            }else{
                printf("No\n");
            }

            destroi(&A);
            destroi(&estacao);
            destroi(&B);
        }
    }

    return 0;
}

Last updated