#define OK 0
#define erro_nos_dados 1 
#define erro_na_leitura_de_arquivo 2 
#define erro_na_alocacao_de_memoria 3 
#define READ_ONLY "r" 
#define el(k) (els+k-1)

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

struct elemento
  {
    int id;
    int g_entr;
    struct sucessor *topo_suc;
    struct elemento *prox_ord;
    struct elemento *prox_fila;
  };

struct sucessor
  {
    struct elemento *id;
    struct sucessor *prox_suc;
  };

int status = OK;
char *nome_do_prog;
char *nome_do_arq;
FILE *arquivo = NULL;

main (argc, argv)
     int argc;
     char **argv;
{
  int n;
  int n_proc = 0;

  struct elemento *els;
  struct elemento *sol = NULL;

  struct elemento *comeco, *fim;

  nome_do_prog = argv[0];

  if (argc > 1)
    {
      nome_do_arq = argv[1];
      arquivo = fopen (nome_do_arq, READ_ONLY);
      if (arquivo == NULL)
	{
	  status = erro_na_leitura_de_arquivo;
	  fprintf (stderr, "%s: Erro na abertura do arquivo %s\n", nome_do_prog,
		   nome_do_arq);
	  exit (status);
	}
    }

  {
    int scanf_args;

    if (arquivo)
      scanf_args = fscanf (arquivo, "%d", &n);
    else
      scanf_args = scanf ("%d", &n);
    if (scanf_args < 1)
      {
	status = erro_nos_dados;
	fprintf (stderr, "%s: Erro na leitura do numero de elementos.\n",
		 nome_do_prog);
	exit (status);
      }
    {
      int k;
      struct elemento *ptr;
      els = (struct elemento *) calloc (n, sizeof (struct elemento));

      if (els==NULL) { /* faltou memória... */
        status=erro_na_alocacao_de_memoria;
        fprintf(stderr, "%s: Faltou memoria!\n", nome_do_prog);
        exit(status);
      }

      for (ptr = els, k = 1; ptr < els + n; ptr++, k++)
	{
	  ptr->id = k;
	  ptr->g_entr = 0;
	  ptr->topo_suc = NULL;
	  ptr->prox_ord = ptr->prox_fila = NULL;
	}
    }

    {
      int i, j;
      int scanf_args;

      int ha_pares_para_ler = 1;

      while (ha_pares_para_ler)
	{
	  if (arquivo)
	    scanf_args = fscanf (arquivo, "%d %d", &i, &j);
	  else
	    scanf_args = scanf ("%d %d", &i, &j);
	  if (scanf_args < 2)
	    ha_pares_para_ler = 0;
	  else
	    {
	      struct sucessor *ptr;
	      ptr = (struct sucessor *) malloc (sizeof (struct sucessor));

              if (ptr==NULL) { /* faltou memória... */
                status=erro_na_alocacao_de_memoria;
                fprintf(stderr, "%s: Faltou memoria!\n", nome_do_prog);
                exit(status);
              }

	      ptr->id = el (j);
	      el (j)->g_entr++;
	      ptr->prox_suc = el (i)->topo_suc;
	      el (i)->topo_suc = ptr;

	    }
	}
    }

    if (arquivo)
      fclose (arquivo);
  }

  {
    int k;
    comeco = fim = NULL;
    for (k = 1; k <= n; k++)
      if (el (k)->g_entr == 0)
	if (comeco == NULL)
	  fim = comeco = el (k);
	else
	  {
	    fim->prox_fila = el (k);
	    fim = el (k);
	  }
  }

  while (comeco)
    {
      struct sucessor *ptr, *tmp;
      ptr = comeco->topo_suc;
      while (ptr)
	{
	  ptr->id->g_entr--;
	  if (ptr->id->g_entr == 0)
	    {
	      ptr->id->prox_fila = NULL;
	      fim->prox_fila = ptr->id;
	      fim = ptr->id;
	    }
	  tmp = ptr;
	  ptr = ptr->prox_suc;
	  free (tmp);
	}

      comeco->prox_ord = sol;
      sol = comeco;

      n_proc++;

      comeco = comeco->prox_fila;
    }

  if (n_proc < n)
    {
      fprintf (stderr, "%s: Erro nos dados de entrada; ha ciclos.\n",
	       nome_do_prog);
      printf ("Vai aqui a lista sol atual...\n");
      {
	struct elemento *ptr, *lista_final;
	lista_final = NULL;
	while (sol)
	  {
	    ptr = sol;
	    sol = sol->prox_ord;
	    ptr->prox_ord = lista_final;
	    lista_final = ptr;
	  }
	for (ptr = lista_final; ptr; ptr = ptr->prox_ord)
	  printf ("%d ", ptr->id);
	printf ("\n");
      }

      status = erro_nos_dados;
      exit (status);
    }

  printf ("Uma ordenacao topologica desta ordem parcial e como segue:\n");
  {
    struct elemento *ptr, *lista_final;
    lista_final = NULL;
    while (sol)
      {
	ptr = sol;
	sol = sol->prox_ord;
	ptr->prox_ord = lista_final;
	lista_final = ptr;
      }
    for (ptr = lista_final; ptr; ptr = ptr->prox_ord)
      printf ("%d ", ptr->id);
    printf ("\n");
  }

  exit (status);
}



