Ir para o conteúdo
Localhost

ONI'2013

Mensagens Recomendadas

HappyHippyHippo

eu vou me inscr .....

espera, eu não estou no secundário ... isso foi à 18 anos atrás ... darn ...

bem, fica para os mais novos :D


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
polska

eu vou me inscr .....

espera, eu não estou no secundário ... isso foi à 18 anos atrás ... darn ...

bem, fica para os mais novos :D

ahahah :D

Bem, podem contar de certeza com a minha inscrição!

Editado por polska

Corrige um sábio e ele mais sábio ficará. Corrige um ignorante e um inimigo ganharás.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
SirDave

Eu já me inscrevi!


Be nice to see your eyes, blink them from time to time to relax your retina when using the computer. Blink now!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
SirDave

Já abriram os servidores de treino no Mooshaq, mas está tudo muito parado, sim.

Editado por SirDave

Be nice to see your eyes, blink them from time to time to relax your retina when using the computer. Blink now!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

A altura de treinar é agora para ter tempo de aprender alguma coisa.

Se precisarem de ajuda nos exercícios digam.


"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
polska

Já está mais mexido, a didaxis leva alunos como o caraças! É isso que é preciso :)


Corrige um sábio e ele mais sábio ficará. Corrige um ignorante e um inimigo ganharás.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
polska

Já agora, este foi o primeiro problema que tentei fazer no servidor de treino das qualificações, tive TLE (33%) ..

Não esperava nem de perto os 100% com a minha solução, mas esperava pelo menos os 50%, a minha ideia é ordenar as alturas de forma crescente, e ordenar também os números de ordem, sendo que se as alturas forem iguais ordeno os números de ordem de forma decrescente, isto porque depois quando recebo os intervalos pretendidos, percorro as alturas do fim para o início e quando encontrar um número de ordem que se encontre nesse intervalo posso logo imprimir a altura (porque sei que é a maior possivel nesse intervalo), e posso imprimir o número de ordem porque está ordenado crescentemente.. E depois continuo o loop até encontrar o próximo prédio que se encontre no intervalo mas que a altura seja diferente da primeira imprimida (a maior) .. Será que é o quick sort que está a atrasar a solução, ou não estou a encarar de forma correcta o problema?

//QUALIFICAÇÃO 2009 - PROBLEMA A: DUBAI

#include <stdio.h>

int alturas[50000], numeros_ordem[50000];

void quick_sort(int esq, int dir)
{
       int i = esq, j = dir, tmp;
       int pivot = alturas[(i+j)/2];
       int pivot_indice = numeros_ordem[(i+j)/2];

       /* divisória */
       while(i<=j)
       {

               while(alturas[i]<pivot || (alturas[i]==pivot && numeros_ordem[i]>pivot_indice)) //se quiser ordenar indices pela ordem crescente -> while(alturas[i]<pivot || (alturas[i]==pivot && numeros_ordem[i]<pivot_indice))
                       i++;
               while(alturas[j]>pivot || (alturas[j]==pivot && numeros_ordem[j]<pivot_indice)) //se quiser ordenar iidices pela ordem crescente -> while(alturas[j]>pivot || (alturas[j]==pivot && numeros_ordem[j]>pivot_indice))
                       j--;        

               if(i<=j)
               {
                   tmp = alturas[j];
                   alturas[j] = alturas[i];
                   alturas[i] = tmp;

                   tmp = numeros_ordem[j];
                   numeros_ordem[j] = numeros_ordem[i];
                   numeros_ordem[i] = tmp;

                   i++; j--;
               }
       };

       /* recursividade */
       if(j > esq)
               quick_sort(esq, j);
       if(i < dir)
               quick_sort(i, dir);
}

int main()
{
   int N, i, j, F, inf, sup, found, max;

   scanf("%d", &N);
   for(i=0; i<N; i++)
   {
       scanf("%d", &alturas[i]);
       numeros_ordem[i] = i+1;
   }

   quick_sort(0, N-1);

   scanf("%d", &F);
   for(i=0; i<F; i++)
   {
       scanf("%d %d", &inf, ⊃);

       found = 0;
       for(j=N-1; j>=0; j--)
       {
           if(numeros_ordem[j] >= inf && numeros_ordem[j] <= sup)
           {
               if(found == 0)
               {
                   found = 1;
                   max = alturas[j];
                   printf("%d %d", max, numeros_ordem[j]);
               }
               else if(alturas[j] == max)
                   printf(" %d", numeros_ordem[j]);
               else
               {
                   printf("\n");
                   break;
               }
           }
       }
   }

   return 0;
}

Editado por polska

Corrige um sábio e ele mais sábio ficará. Corrige um ignorante e um inimigo ganharás.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

Nota: o mooshak só reporta o erro mais grave. Se tens wrong answers e TLE, o judge reporta TLE.

Teres o \n dentro do ciclo não é boa ideia. se as alturas forem todas iguais, não imprimes o \n

Na prática, ordenar só se ajuda se tiveres sorte com o input. Se tens 200 alturas e se se pede só da 100 à 110, podes estar a percorrer todas nesse ciclo. Assim, não vale a pena ordenar

PS: acho muito bem aprenderes o quick sort e a sua implementação, mas na prática é muito melhor aprender a usar o sort() do c++.

// warning: codigo escrito directamente no forum sem testar.
#include <algorithm> // sort
using namespace std;

// assim
int alturas[MAX], numeros_ordem[MAX] , indices[MAX]; // inicialmente, indices = {0,1,2,3,... N-1}

bool compara(int i, int j) {
 if (alturas[i] == alturas[j])
	 return numeros_ordem[i] < numeros_ordem[j];
return alturas[i] < alturas[j];
}
int main() {
// popular alturas[], numeros_ordem[] e indices[]
sort( indices , indices + N, compara );
// indices[i] = indice do i-ésimo (altura, numero_ordem) mais pequeno
}

// ou
pair<int, int> alturas[MAX];  // par com first = altura , second = numero de ordem

int main() {
// popular alturas
sort( alturas, alturas + N );
// alturas[i].first = altura, altura[i].second = numero de ordem, do i-ésimo (altura, numero_ordem) mais pequeno
}

Editado por mogers

"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
polska

Hummm realmente não me lembrei do caso do '\n' ! Vou corrigir isso!

Eu no início pensei se devia ou não ordenar, mas acabei por faze-lo .. Eu só não uso o sort do c++ porque não estou muito acostumado a misturar C com C++, se bem que sei que não tem mal nenhum e que usar o sort não é complicado.. Mas também tinha dúvida na função de comparar, antes de implementar o quick sort eu ia usar o qsort da stdlib, mas eu não sabia como fazer a função de comparar para quando os indices fossem iguais.. Mas é igual à maneira como fizeste nesse código para o sort certo?


Corrige um sábio e ele mais sábio ficará. Corrige um ignorante e um inimigo ganharás.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

Não, o qsort é um pouco diferente. A função de comparação a usar no qsort tem de receber void*, enquanto que na versão em C++ não.

http://stackoverflow.com/questions/327893/how-to-write-a-compare-function-for-qsort-from-stdlib

voltando ao problema em causa, se procurares no forum encontras discussões sobre soluções acerca do problema. visto que este problema necessita de técnicas menos comuns, acho que deves lê-las.

edit: é importante referir que o sort() da <algorithm> implementa um algoritmo que garante O(N log N), isto é, não tem O(N^2) como worst-case como a qsort (que usa o quick sort).

Editado por mogers

"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

atirei este código ao gcc e correu bem (número de ordenações = 0)

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

#define MAX_BUILDINGS 50000
#define MAX_PHOTOS 50000

#define INPUT_FILE "input.txt"

typedef struct
{
   int height;
   int shadow;
   int shadowing;
} Building;

int main()
{
   Building buildings[MAX_BUILDINGS];
   int n_buildings;
   int n_photos;
   int min, max;
   int i, j;

   FILE * fd = NULL;

   memset(buildings, 0, sizeof(Building) * MAX_BUILDINGS);

   if ((fd = fopen(INPUT_FILE, "r")) == NULL)
   {
       fprintf(stderr, "Erro de abertura do ficheiro de input\n");
       return EXIT_FAILURE;
   }

   if (fscanf(fd, "%d", &n_buildings) != 1) {
       fprintf(stderr, "Erro de leitura do numero de edificios\n");
       fclose(fd);

       return EXIT_FAILURE;
   }

   for (i = 0; i < n_buildings; i++)
   {
       if (fscanf(fd, "%d", &buildings[i].height) != 1) {
           fprintf(stderr, "Erro de leitura da altura do edificio %d\n", i);
           fclose(fd);

           return EXIT_FAILURE;
       }

       j = i - 1;
       while (j >= 0 && buildings[j].height < buildings[i].height)
       {
           j = buildings[j].shadow; // edit : performance
       }

       buildings[i].shadow = j;

       if (buildings[j].height == buildings[i].height)
       {
           buildings[j].shadowing = i;
       }
   }

   if (fscanf(fd, "%d", &n_photos) != 1) {
       fprintf(stderr, "Erro de leitura do numero de fotos\n");
       fclose(fd);

       return EXIT_FAILURE;
   }

   for (i = 0; i < n_photos; i++)
   {
       if (fscanf(fd, "%d %d", &min, &max) != 2) {
           fprintf(stderr, "Erro de leitura dos limites da fotografia\n");
           fclose(fd);

           return EXIT_FAILURE;
       }
       min--;
       max--;

       j = max;
       while (buildings[j].shadow > min)
       {
           j = buildings[j].shadow;
       }

       printf("%d", buildings[j].height);
       while (j != 0)
       {
           printf(" %d", j + 1);
           j = buildings[j].shadowing;
       }
       printf("\n");
   }

   fclose(fd);

   return EXIT_SUCCESS;
}

existe alguma maneira de eu verificar que classificação teria com este código ?

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

Funciona para o exemplo mas não me parece correcto. Exemplo

2
2 2
1
1 2

A resposta deveria ser "2 1 2" mas dá "2 2".

Uma abordagem dessas toma tempo O(N^2) logo na construção do shadow, com um array crescente de alturas. Por isso teria no máximo uns 50 a 60 pontos acho eu.


"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

Funciona para o exemplo mas não me parece correcto. Exemplo

2
2 2
1
1 2

A resposta deveria ser "2 1 2" mas dá "2 2".

sim, com uma correcção esse problema é resolvido, até porque já sei a razão :D

// http://www.dcc.fc.up.pt/oni/problemas/2009/qualificacao/probA.html

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

#define MAX_BUILDINGS 50000
#define MAX_PHOTOS 50000

#define INPUT_FILE "input.txt"

typedef struct
{
int height;
int shadow;
int shadowing;
} Building;

int main()
{
Building buildings[MAX_BUILDINGS];
int n_buildings;
int n_photos;
int min, max;
int i, j;

FILE * fd = NULL;

memset(buildings, 0, sizeof(Building) * MAX_BUILDINGS);

if ((fd = fopen(INPUT_FILE, "r")) == NULL)
{
	fprintf(stderr, "Erro de abertura do ficheiro de input\n");
	return EXIT_FAILURE;
}

if (fscanf(fd, "%d", &n_buildings) != 1) {
	fprintf(stderr, "Erro de leitura do numero de edificios\n");
	fclose(fd);

	return EXIT_FAILURE;
}

for (i = 0; i < n_buildings; i++)
{
	if (fscanf(fd, "%d", &buildings[i].height) != 1) {
		fprintf(stderr, "Erro de leitura da altura do edificio %d\n", i);
		fclose(fd);

		return EXIT_FAILURE;
	}

	j = i - 1;
	while (j >= 0 && buildings[j].height < buildings[i].height)
	{
		j = buildings[j].shadow; // edit : performance
	}

	buildings[i].shadow = j;

	if (buildings[0].height == buildings[i].height)
	{
		buildings[j].shadowing = i;
	}
}

if (fscanf(fd, "%d", &n_photos) != 1) {
	fprintf(stderr, "Erro de leitura do numero de fotos\n");
	fclose(fd);

	return EXIT_FAILURE;
}

for (i = 0; i < n_photos; i++)
{
	if (fscanf(fd, "%d %d", &min, &max) != 2) {
		fprintf(stderr, "Erro de leitura dos limites da fotografia\n");
		fclose(fd);

		return EXIT_FAILURE;
	}
	min--;
	max--;

	j = max;
	while (buildings[j].shadow >= min)
	{
		j = buildings[j].shadow;
	}

	printf("%d", buildings[j].height);
	printf(" %d", j + 1);

	j = buildings[j].shadowing;
	while (j != 0)
	{
		printf(" %d", j + 1);
		j = buildings[j].shadowing;
	}
	printf("\n");
}



fclose(fd);

return EXIT_SUCCESS;
}

---------------

Uma abordagem dessas toma tempo O(N^2) logo na construção do shadow, com um array crescente de alturas. Por isso teria no máximo uns 50 a 60 pontos acho eu.

faz bem as contas ...

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
polska

Eu agora que vejo, estava a ser mesmo estúpido . eu tenho os limites, um for de limite inferior ao superior chega para fazer o mesmo que eu fiz com tanta ordenação.. ai jesus, estou maluco :cheesygrin: . Mas já estive a ver essas tais técnicas, vou melhorar isto!


Corrige um sábio e ele mais sábio ficará. Corrige um ignorante e um inimigo ganharás.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

faz bem as contas ...

Não tenho os testes do treino e o treino só está disponivel aos concorrentes. Pelo enunciado, uma solução com essa complexidade temporal cumpria o requisito dos 50%, talvez consiga um pouco mais, daí talvez os 60 pontos.

Editado por mogers

"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

// http://www.dcc.fc.up.pt/oni/problemas/2009/qualificacao/probA.html

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

#define MAX_BUILDINGS 50000
#define MAX_PHOTOS 50000

#define INPUT_FILE "input.txt"

typedef struct
{
int height;
int shadow;
int shadowing;
} Building;

int main()
{
Building buildings[MAX_BUILDINGS];
int n_buildings;
int n_photos;
int min, max;
int i, j;

FILE * fd = NULL;

memset(buildings, 0, sizeof(Building) * MAX_BUILDINGS);

if ((fd = fopen(INPUT_FILE, "r")) == NULL)
{
	fprintf(stderr, "Erro de abertura do ficheiro de input\n");
	return EXIT_FAILURE;
}

if (fscanf(fd, "%d", &n_buildings) != 1) {
	fprintf(stderr, "Erro de leitura do numero de edificios\n");
	fclose(fd);

	return EXIT_FAILURE;
}

for (i = 0; i < n_buildings; i++)
{
	if (fscanf(fd, "%d", &buildings[i].height) != 1) {
		fprintf(stderr, "Erro de leitura da altura do edificio %d\n", i);
		fclose(fd);

		return EXIT_FAILURE;
	}

	j = i - 1;
	while (j >= 0 && buildings[j].height < buildings[i].height)
	{
		j = buildings[j].shadow; // edit : performance
	}

	buildings[i].shadow = j;

	if (buildings[0].height == buildings[i].height)
	{
		buildings[j].shadowing = i;
	}
}

if (fscanf(fd, "%d", &n_photos) != 1) {
	fprintf(stderr, "Erro de leitura do numero de fotos\n");
	fclose(fd);

	return EXIT_FAILURE;
}

for (i = 0; i < n_photos; i++)
{
	if (fscanf(fd, "%d %d", &min, &max) != 2) {
		fprintf(stderr, "Erro de leitura dos limites da fotografia\n");
		fclose(fd);

		return EXIT_FAILURE;
	}
	min--;
	max--;

	j = max;
	while (buildings[j].shadow >= min)
	{
		j = buildings[j].shadow;
	}

	printf("%d", buildings[j].height);
	printf(" %d", j + 1);

	j = buildings[j].shadowing;
	while (j != 0)
	{
		printf(" %d", j + 1);
		j = buildings[j].shadowing;
	}
	printf("\n");
}



fclose(fd);

return EXIT_SUCCESS;
}

Isso parece-me apenas um hack para a posição 0.


5
1 2 2 2 2
1
1 5

Deveria dar "2 2 3 4 5" mas dá "2 2".

Posso continuar a criar casos de teste, mas não me parece que essa abordagem vá no bom caminho...

Este tutorial explica uma técnica possível para resolver o problema.


"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

Isso parece-me apenas um hack para a posição 0.

Código :

5

1 2 2 2 2

1

1 5

Deveria dar "2 2 3 4 5" mas dá "2 2".

Posso continuar a criar casos de teste, mas não me parece que essa abordagem vá no bom caminho...

... criei um erro ao alterar o código antigo, estava a ver algo e fiz bronca ...

// http://www.dcc.fc.up.pt/oni/problemas/2009/qualificacao/probA.html

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

#define MAX_BUILDINGS 50000
#define MAX_PHOTOS 50000

#define INPUT_FILE "input.txt"

typedef struct
{
int height;
int shadow;
int shadowing;
} Building;

int main()
{
Building buildings[MAX_BUILDINGS];
int n_buildings;
int n_photos;
int min, max;
int i, j;

FILE * fd = NULL;

memset(buildings, 0, sizeof(Building) * MAX_BUILDINGS);

if ((fd = fopen(INPUT_FILE, "r")) == NULL)
{
	fprintf(stderr, "Erro de abertura do ficheiro de input\n");
	return EXIT_FAILURE;
}

if (fscanf(fd, "%d", &n_buildings) != 1) {
	fprintf(stderr, "Erro de leitura do numero de edificios\n");
	fclose(fd);

	return EXIT_FAILURE;
}

for (i = 0; i < n_buildings; i++)
{
	if (fscanf(fd, "%d", &buildings[i].height) != 1) {
		fprintf(stderr, "Erro de leitura da altura do edificio %d\n", i);
		fclose(fd);

		return EXIT_FAILURE;
	}

	j = i - 1;
	while (j >= 0 && buildings[j].height < buildings[i].height)
	{
		j = buildings[j].shadow; // edit : performance
	}

	buildings[i].shadow = j;

	if (buildings[j].height == buildings[i].height) // <- isto não era para alterar !!!!
	{
		buildings[j].shadowing = i;
	}
}

if (fscanf(fd, "%d", &n_photos) != 1) {
	fprintf(stderr, "Erro de leitura do numero de fotos\n");
	fclose(fd);

	return EXIT_FAILURE;
}

for (i = 0; i < n_photos; i++)
{
	if (fscanf(fd, "%d %d", &min, &max) != 2) {
		fprintf(stderr, "Erro de leitura dos limites da fotografia\n");
		fclose(fd);

		return EXIT_FAILURE;
	}
	min--;
	max--;

	j = max;
	while (buildings[j].shadow >= min)
	{
		j = buildings[j].shadow;
	}

	printf("%d", buildings[j].height);
	printf(" %d", j + 1);

	j = buildings[j].shadowing;
	while (j != 0)
	{
		printf(" %d", j + 1);
		j = buildings[j].shadowing;
	}
	printf("\n");
}

fclose(fd);

return EXIT_SUCCESS;
}

Este tutorial explica uma técnica possível para resolver o problema.

não é minha intenção resolver como todos os outros, é fazer exactamente diferente dos outros ...

e se achas que resolver isto me faz grande diferença, estás muito enganado :D estou simplesmente a espairecer do trabalho ...


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

Não estás a verificar os limites do teu output.


3
2 1 2
1
1 2

Dá "2 1 3" em vez de "2 1".

e se achas que resolver isto me faz grande diferença, estás muito enganado :D

Muito gostas de mandar estas bocas quando te apontam algum erro :cheesygrin: se não tivesses alguma motivação, não estarias a tentar resolver o exercício ;)


"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
polska

@Mogers, o que é necessário é apenas o RMQ certo?

ps: já tirei ordenação e etc e já deu 60 e tal % .. sem complicações :b

Editado por polska

Corrige um sábio e ele mais sábio ficará. Corrige um ignorante e um inimigo ganharás.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

Muito gostas de mandar estas bocas quando te apontam algum erro :cheesygrin: se não tivesses alguma motivação, não estarias a tentar resolver o exercício ;)

como queiras

ps : o código que tenho dá 2 1 3 ...

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

@Mogers, o que é necessário é apenas o RMQ certo?

Sim. O(N sqrt(N)) funciona bem e é a versão mais simples de implementar.


"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

ps : o código que tenho dá 2 1 3 ...

A query é dos indices 1 a 2. A resposta é "2 1".


"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.