Foro de elhacker.net

Programación => Ejercicios => Mensaje iniciado por: ghastlyX en 6 Septiembre 2008, 03:03 am



Título: Programación algorítmica: unos problemillas
Publicado por: ghastlyX en 6 Septiembre 2008, 03:03 am
A raíz de ver los problemas de ohk, me ha gustado la idea y voy a poner también algunos problemas, al mismo estilo de entrada-salida que en los concursos de programación.

Por ahora pondré un par, uno facilísimo (triangulos.pdf) y otro algo más complejo (minas.pdf), si veo que gusta ya me inventaré más de diferentes tipos.

Los pongo adjuntos en pdf. Sobre el primero no hay nada que decir, es muy sencillo, respecto al segundo, como pone en el enunciado, no se puede hacer recursivamente puesto que es muy lento, buscad otro tipo de solución más dinámica xDD

En cuanto a los lenguajes, que cada uno lo haga con aquel que use y lo postee, puesto que así no queda limitado a ningún lenguaje, poniendo comentarios para que el resto podamos entender que hace su programa si no conocemos el lenguaje. La solución la daré si es necesaria en pseudocódigo.

Un saludo de ghastlyX ;)


Título: Re: Programación algorítmica: unos problemillas
Publicado por: :ohk<any> en 6 Septiembre 2008, 04:37 am
Hola :D

Hombre están buenos tus ejercicios, aunque el de las minas es mas complejo, por ahora voy a resolver el primero, espero no tardarme demasiado  :P

Un saludo

OHK


Título: Re: Programación algorítmica: unos problemillas
Publicado por: GroK en 6 Septiembre 2008, 06:51 am
Hola ;)

Me han parecido interesantes los ejercicios, voy a postear el primero, si te parece bien:

En C:

Código
  1. #include <stdio.h>
  2.  
  3. int main (void)
  4. {
  5. int i, j, n;
  6.  
  7. printf ("Introduce altura de la pared: ");
  8. scanf ("%d", &n);
  9. for (i = n; i >= 1; i--) { /* Bucle desde la cima hasta la base */
  10. j = i; /* 'j' servira para saber las veces que se repiten los numeros en cada nivel de la piramide */
  11. while (j <= n) {
  12. printf ("%d ", i); /* Imprimimos el numero del nivel... */
  13. j++;
  14. } /* ...tantas veces como niveles alejados de la cima estemos */
  15. printf ("\n");
  16. }
  17. printf ("\n");
  18. return 0;
  19. }



En Pascal:

Código
  1. PROGRAM Triangulos;
  2.  
  3. VAR
  4. i, j, n : Byte;
  5.  
  6. BEGIN
  7.  
  8. Write ('Introduce altura de la pared: ');
  9. ReadLn (n);
  10. For i := n DownTo 1 Do
  11. Begin
  12. j := i;
  13. While (j <= n) Do
  14. Begin
  15. Write (i, ' ');
  16. Inc (j);
  17. End;
  18. WriteLn ();
  19. End;
  20. WriteLn ();
  21.  
  22. END.



Igual se pueden optimizar algo mas, pero bueno... En cuanto pueda intentare el segundo tambien, a ver que tal

Gracias y saludos


Título: Re: Programación algorítmica: unos problemillas
Publicado por: ghastlyX en 6 Septiembre 2008, 14:08 pm
Vale, el código está bien, aunque tal y como dije, la idea es que no pidas la entrada, tú simplemente has de hacer un programa que la reciba. Y por cierto, cuidado que has puesto espacios entre los números, eso en un concurso de programación te lo darían como mal. Aunque como lo importante es la idea y esta es correcta, el problema lo doy por resuelto. Si alguien quiere aportar más soluciones para este serán bievenidas. Ahora a por el de las minas :P

El primero en C++ lo tenía así, un poco más corto:
Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main()
  5. {
  6.    int n, i = 1;
  7.    cin >> n;  //Recogemos n
  8.    while(n) //Mientras n no sea cero
  9.    {
  10.            for(int k = 0; k < i; k++) cout << n;  //Imprimimos i veces n, para una i inicial de 1
  11.            i++; //Aumentamos en 1 i para el siguiente nivel
  12.            n--; //Disminuimos en 1 n
  13.            cout << endl; //Imprimimos un salto de línea
  14.    }
  15. }

Pero es lo mismo, la idea es como lo has hecho.

Un saludo de ghastlyX ;)


Título: Re: Programación algorítmica: unos problemillas
Publicado por: GroK en 6 Septiembre 2008, 16:48 pm
Guay :D

Lo del espacio despues de los numeros lo puse deliberadamente, pensando que asi es mas legible... Pero bueno es igual, se quita y ya esta xD No sabia eso de los concursos, me lo apuntare

Ah, y me gusta tu codigo, te quedo mas corto, tiene estilo :P

Ahora a por el de las minas, como tu dices. Saludos




Título: Re: Programación algorítmica: unos problemillas
Publicado por: chrominum en 6 Septiembre 2008, 21:48 pm
Mi solución en c# del ejercicio de los Triángulos:

Código
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4.  
  5. namespace Triangulos
  6. {
  7.    class TriangulosApp
  8.    {
  9.        static void Main(string[] args)
  10.        {
  11.            byte metros, nivel = 1, i;
  12.            Console.Write("Introduce los metros de la pared: ");
  13.            metros = Convert.ToByte(Console.ReadLine());
  14.            while (metros > 0 && metros < 10)
  15.            {
  16.                for (i = 0; i < nivel; i++)
  17.                    Console.Write(metros);
  18.                Console.WriteLine();
  19.                metros--;
  20.                nivel++;
  21.            }
  22.            Console.ReadKey();
  23.        }
  24.    }
  25. }

Y mi otra soluciona al problema de los triángulos haciendo uso de los RepUnit (http://en.wikipedia.org/wiki/Repunit) (para conseguir cogido mas corto):

Código
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4.  
  5. namespace TriangulosRepUnit
  6. {
  7.    class TriangulosRepUnitApp
  8.    {
  9.        static void Main(string[] args)
  10.        {
  11.            byte metros, nivel;
  12.            Console.Write("Introduce los metros de la pared: ");
  13.            metros = Convert.ToByte(Console.ReadLine());
  14.            for (nivel = 1; metros > 0 && metros < 10; nivel++)
  15.            {
  16.                Console.WriteLine((Math.Pow(10, nivel) - 1) / 9 * metros);
  17.                metros--;
  18.            }
  19.            Console.ReadKey();
  20.        }
  21.    }
  22. }


Título: Re: Programación algorítmica: unos problemillas
Publicado por: ghastlyX en 7 Septiembre 2008, 00:01 am
Son correctas ambas, me ha gustado la segunda, es una forma original de resolverlo, más de tipo matemática que no directa. Eso sí, como ya he dicho, no hay que pedir la entrada con lo de "Introduce los metros de la pared", simplemente recoged los datos, al estilo de UVa, USACO, OIE, IOI, ACM, Topcoder, etc. Poniendo eso en los concursos os daría error, puesto que la salida que produce tiene que ser idéntica a los ejemplos, y en ellos no aparecen peticiones de entrada de datos. Bueno, ya que el de los triángulos está resuelto, intentad el de las minas, que es algo más complejo.

Se podría hacer recursivamente, mirando TODOS los caminos desde cada parcela, pero es brutalmente lento, una solución recursiva no será considerada correcta. En mi primer post di una gran pista de cómo resolverlo, la repetiré: buscad una solución más dinámica!

Un saludo de ghastlyX ;)


Título: Re: Programación algorítmica: unos problemillas
Publicado por: ghastlyX en 8 Septiembre 2008, 00:43 am
Bueno, voy a poner uno nuevo, esta vez de grafos, lo dejo adjunto. A ver si alguien da ya una solución para el de las minas, para el que no se haya dado cuenta con las pistas o no conozca ese tipo de problemas, es de programación dinámica. Si nadie publica nada tendré que dar yo la solución :P

Un saludo de ghastlyX ;)


Título: Re: Programación algorítmica: unos problemillas
Publicado por: GroK en 8 Septiembre 2008, 03:46 am
Si nadie publica nada tendré que dar yo la solución :P

No!! Esperame xDD Tengo un examen mañana y por eso no lo he intentado hasta ahora, no he tenido tiempo, pero cuando llegue me pongo (encima en el examen me cae programacion dinamica :xD Y eso me lo se bien :P)

Saludos


Título: Re: Programación algorítmica: unos problemillas
Publicado por: ghastlyX en 8 Septiembre 2008, 20:47 pm
OK, me esperaré un poco más y mientras si eso quizá ponga alguno nuevo más. Por ahora hay tres: uno directo, otro DP y otro de grafos.

Un saludo de ghastlyX ;)

PD: Hay que ver, que a muchos los sacan de APIs, hooks y ese tipo de programación y se pierden xDD


Título: Re: Programación algorítmica: unos problemillas
Publicado por: GroK en 9 Septiembre 2008, 02:39 am
Buenas, ya he vuelto :D

Pues al final me he metido con el de grafos, me ha gustado mucho xD Y por cierto, decirte que me falto implementarle lo de varios casos por falta de tiempo, es decir, la entrada al programa es identica, solo que obvia el numero de casos y solo te resolvera el primero, si quieres probar otros casos hay que ejecutar de nuevo el programa (sorry, obviamente no presentaria eso asi en un concurso xDD)

Pero nada, queria que simplemente le echaras un vistazo a la parte principal del programa, el algoritmo y tal que es lo que importa al fin y al cabo, y ver que cambiarias tu o como lo harias (seguro que se puede hacer mas eficientemente que el mio :))

Aqui te lo dejo (Otra cosa, solo lo he hecho en pascal, en cuanto vuelva a tener un rato disponible intentare pasarlo a C a ver):

Código
  1. program circulos;
  2.  
  3. const
  4. MAX = 20;
  5.  
  6. type
  7. TValores  = Record
  8.                Asignado : boolean;
  9. Color       : boolean; { 'True' = Verde; 'False' = Amarillo }
  10. End;
  11. TVertices = array [0..MAX] of TValores;
  12. TCasos = array [1..MAX] of TVertices;
  13.  
  14. var
  15. nCasos : integer;
  16. nVertices : integer;
  17. nAristas : integer;
  18. inicio, fin  : integer;
  19. vertices : TVertices;
  20. casos : TCasos;
  21. flag : boolean;
  22. i : integer;
  23.  
  24. procedure init_vertices (var c : TCasos);
  25.  
  26. var
  27. i, j : integer;
  28.  
  29. begin
  30.  
  31. for i := 1 to MAX do
  32. for j := 0 to MAX do
  33. begin
  34. c[i][j].Asignado := false;
  35. c[i][j].Color := false;
  36. end;
  37.  
  38. end;
  39.  
  40. function evalua (var v : TVertices; inicio, fin : integer) : boolean;
  41.  
  42. begin
  43.  
  44. if (v[inicio].Asignado = false) and (v[fin].Asignado = false) then { si ninguno ha sido asignado aun }
  45. begin
  46. v[inicio].Asignado := true;
  47. v[inicio].Color := true;
  48. v[fin].Asignado := true;
  49. v[fin].Color := false;
  50. evalua := true;
  51. end
  52. else
  53. begin
  54. if (v[inicio].Asignado) xor (v[fin].Asignado) then { si uno de los dos esta asignado }
  55. begin
  56. if v[fin].Asignado = false then
  57. begin
  58. v[fin].Asignado := true; { lo marcamos como coloreado }
  59. v[fin].Color := not v[inicio].Color; { y le ponemos el color contrario al del otro vertice }
  60. end
  61. else
  62. begin  { en caso de que el que no estuviese coloreado aun fuera el vertice inicial, lo mismo para este }
  63. v[inicio].Asignado := true;
  64. v[inicio].Color := not v[fin].Color;
  65. end;
  66. evalua := true;
  67. end
  68. else
  69. begin  { si entramos aqui es porque ambos ya estan coloreados, comprobemos si es incompatible }
  70. if v[inicio].Color = v[fin].Color then
  71. evalua := false
  72. else
  73. evalua := true;
  74. end;
  75. end;
  76.  
  77. end;
  78.  
  79. { -- MAIN --}
  80.  
  81. begin  
  82.  
  83. init_vertices (casos);
  84. flag := true;
  85. readln (nCasos);
  86. readln (nVertices, nAristas);
  87. for i := 1 to nAristas do
  88. begin
  89. readln (inicio, fin);
  90. flag := flag and (evalua (vertices, inicio, fin));
  91. end;
  92. if flag then
  93. writeln ('Miguel, a pintar')
  94. else
  95. writeln ('No pierdas el tiempo');
  96.  
  97. end.

Ale, ahi lo tienes, dispara :P

Decirte tambien que voy a estar fuera hasta el viernes o asi, en cuanto vuelva a estar online le meto mano al susodicho problema nº 2, y tal vez traducir este a C

Gracias de nuevo por tus problemas, de verdad que son muy interesantes y me he entretenido mucho con ellos, sobre todo el ultimo claro (pa haber salido de un examen de GRAFOS hoy mismo y ponerme a hacer problemas de GRAFOS... xDD hay que echarle ganas)

Saludos!


Título: Re: Programación algorítmica: unos problemillas
Publicado por: ghastlyX en 9 Septiembre 2008, 19:14 pm
Supongo que estará bien, Pascal no sé, por los comentarios que pones parece que está bien, pero no te lo puedo asegurar. He hecho en cinco minutillos una solución en C++ con comentarios en cada línea, así podrás ver si es lo mismo:
Código
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4.  
  5. //Definimos los colores como constantes
  6. const int VERDE = 0;
  7. const int AMARILLO = 1;
  8.  
  9. bool dfs(vector<vector<int> >& grafo, int nodo, int color, vector<int>& color_nodo)
  10. {
  11.     bool flag = true;  //Declaramos el flag como true
  12.     for(int i = 0; i < grafo[nodo].size(); i++)  //Mientras nuestro nodo tenga conexiones...
  13.     {
  14.             if(color_nodo[grafo[nodo][i]] == - 1) //Si el nodo al que está conectado no está pintado...
  15.             {
  16.                color_nodo[grafo[nodo][i]] = not color;  //Le ponemos el color contrario
  17.                flag = dfs(grafo, grafo[nodo][i], not color, color_nodo);  //flag recibe el valor del DFS en dicho nodo
  18.             }
  19.             else if(color_nodo[grafo[nodo][i]] == color) return false;  //Si tiene el mismo color, es imposible el bicolouring, devolvemos false
  20.     }
  21.     return flag;  //Si no se ha salido antes, devuelve flag.
  22. }            
  23.  
  24. int main()
  25. {
  26.    int q; //Número de casos
  27.    cin >> q; //Recogemos los casos
  28.    while(q--) //Mientras siga habiendo casos...
  29.    {
  30.            int n, p; //Nodos y conexiones respectivamente
  31.            cin >> n >> p; //Recogemos ambos valores
  32.            vector<int> color_nodo(n, -1); //Declaramos un arreglo de tamaño n para guardar el color de cada nodo
  33.            vector<vector<int> > grafo(n); //Declaramos una matriz especificando solamente una dimensión
  34.            while(p--) //Mientras haya conexiones por recoger...
  35.            {
  36.                 int origen, destino;  
  37.                 cin >> origen >> destino;  //Recogemos los nodos de origen y destino
  38. //Ambos nodos están conectados, por lo que hay que poner la conexión hacia ambos lados
  39. //La matriz grafo indicará las conexiones: grafo[i].size() será la el número de conexiones donde cada j de grafo[i][j] es el nodo al que se conecta
  40.                 grafo[origen].push_back(destino);  //Añadimos el nodo al que se conecta, en ambos sentidos
  41.                 grafo[destino].push_back(origen);
  42.            }
  43.            color_nodo[0] = VERDE;  //Al primer nodo le asignamos color verde (puede ser al revés, es un simple número)
  44.            if(dfs(grafo, 0, VERDE, color_nodo)) cout << "Miguel, a pintar" << endl;  //Hacemos DFS y según qué devuelva mostramos una salida u otra
  45.            else cout << "No pierdas el tiempo" << endl;
  46.    }
  47. }

Venga, que seguro que más gente aparte de GroK sabe programar. Quiero una solución para el de las minas :P

Un saludo de ghastlyX ;)


Título: Re: Programación algorítmica: unos problemillas
Publicado por: ghastlyX en 21 Septiembre 2008, 21:50 pm
Pues ante la ausencia de respuestas, aclaro como se hace el de las minas. Recursivamente sería empezar en cada una de las casillas de la primera fila e ir probando cada camino desde ahí. Esto es terriblemente lento además de que probamos más de una vez el mismo camino. La solución es por DP.

Creamos una matriz de carácteres para guardar el mapa y otra del mismo tamaño para almacenar números. Entonces simplemente hay que recorrer dicha matriz: si en la posición hay una mina el número lo ponemos a un máximo declarado antes, de lo contrario será el mínimo entre el de arriba y las dos diagonales de arriba + 1. No hace falta decir que la primera fila ha de valer cero en todas las casillas excepto las que tengan minas. La solución final es el mínimo de todas las posiciones de la última fila.

No pondré más problemas, puesto que no tengo demasiado tiempo y casi nadie se pasa por aquí a resolverlos :P

Un saludo de ghastlyX ;)


Título: Re: Programación algorítmica: unos problemillas
Publicado por: Nakp en 22 Septiembre 2008, 23:29 pm
jeje.. aqui va el mio de triángulos

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main(){
  5. int m, i, j;
  6. scanf("%i",&m);
  7. for(i = m; i >= 1; i--){
  8. for(j = m; j >= i; j--){
  9. printf("%i",i);
  10. }
  11. printf("\n");
  12. }
  13. return 0;
  14. }

acabo de ponerme a hacerlos así que ya hago el de minas (ni lo he leido)

salu2


Título: Re: Programación algorítmica: unos problemillas
Publicado por: Nakp en 25 Septiembre 2008, 02:28 am
Pues ante la ausencia de respuestas, aclaro como se hace el de las minas. Recursivamente sería empezar en cada una de las casillas de la primera fila e ir probando cada camino desde ahí. Esto es terriblemente lento además de que probamos más de una vez el mismo camino. La solución es por DP.

Creamos una matriz de carácteres para guardar el mapa y otra del mismo tamaño para almacenar números. Entonces simplemente hay que recorrer dicha matriz: si en la posición hay una mina el número lo ponemos a un máximo declarado antes, de lo contrario será el mínimo entre el de arriba y las dos diagonales de arriba + 1. No hace falta decir que la primera fila ha de valer cero en todas las casillas excepto las que tengan minas. La solución final es el mínimo de todas las posiciones de la última fila.

No pondré más problemas, puesto que no tengo demasiado tiempo y casi nadie se pasa por aquí a resolverlos :P

Un saludo de ghastlyX ;)

 ahm... que se me hace que se resuelve con una matriz de adyacencia :xD deja un rato libre que no se queda sin solución


Título: Re: Programación algorítmica: unos problemillas
Publicado por: ghastlyX en 25 Septiembre 2008, 19:44 pm
¿Matriz de adyacencia? No es de grafos el problema, es de DP y se resuelve como expliqué en el post anterior, supongo que pensarías en BFS o Dijkstra, pero va de dinámica.

Un saludo de ghastlyX ;)


Título: Re: Programación algorítmica: unos problemillas
Publicado por: Nakp en 26 Septiembre 2008, 07:19 am
¿Matriz de adyacencia? No es de grafos el problema, es de DP y se resuelve como expliqué en el post anterior, supongo que pensarías en BFS o Dijkstra, pero va de dinámica.

Un saludo de ghastlyX ;)

en realidad se me ocurrió warshall pero apenas lo entiendo :¬¬ y en 6 horas tengo un control de lectura! :laugh:


Título: Re: Programación algorítmica: unos problemillas
Publicado por: ghastlyX en 26 Septiembre 2008, 17:07 pm
Pues no te sé decir si por Floyd-Warshall funcionaría, pero si no me equivoco creo que mediante ese algoritmo tienes complejidad cúbica, tal y como he explicado sólo cuadrática. Olvida algoritmos de búsquedas de caminos en grafos para este problema. De hecho, olvida los grafos para este problema, se puede resolver sin haber visto un grafo en la vida.

Un saludo de ghastlyX ;)


Título: Re: Programación algorítmica: unos problemillas
Publicado por: juancho77 en 20 Noviembre 2008, 04:55 am
Citar
Creamos una matriz de carácteres para guardar el mapa y otra del mismo tamaño para almacenar números. Entonces simplemente hay que recorrer dicha matriz: si en la posición hay una mina el número lo ponemos a un máximo declarado antes, de lo contrario será el mínimo entre el de arriba y las dos diagonales de arriba + 1. No hace falta decir que la primera fila ha de valer cero en todas las casillas excepto las que tengan minas. La solución final es el mínimo de todas las posiciones de la última fila.

Ya que estamos. Me tome el trabajo de pasar el algortimo a Java  :-*
Código
  1. import java.io.*;
  2. import java.util.Random;
  3. public class minas {
  4.    public static void main() throws Exception {
  5.        char[][] caracteres;
  6.        int [][] resultado;
  7.        System.out.print("Ingrese cantidad de filas:");
  8.        int filas=Integer.parseInt(br.readLine());
  9.        System.out.print("Ingrese cantidad de columnas:");
  10.        int columnas=Integer.parseInt(br.readLine());
  11.        caracteres=new char[filas][columnas];
  12.        resultado=new int[filas][columnas];
  13.        Random rnd=new Random();
  14.        for (int i=0; i<filas; i++)
  15.        {
  16.            for(int j=0;j<columnas;j++)
  17.            {
  18.                //genero la tabla/////////////
  19.                int aleat=rnd.nextInt(2);
  20.                if (aleat==1)
  21.                    caracteres[i][j]='M';
  22.                    else caracteres[i][j]='L';
  23.                //////////////////////////////
  24.                //
  25.                if (caracteres[i][j]=='M')
  26.                    resultado[i][j]=99;
  27.                else //si esta libre
  28.                {
  29.                    if (i==0) //si es la primera fila
  30.                        resultado[i][j]=0;
  31.                    else //en cualquier otro caso
  32.                    {
  33.                        if ((j>0)&&(j<columnas-1))
  34.                            resultado[i][j]=min(resultado[i-1][j-1]+1,resultado[i-1][j],resultado[i-1][j+1]+1);
  35.                        else if (j==0)
  36.                            resultado[i][j]=min(resultado[i-1][j],resultado[i-1][j+1]+1,99);
  37.                             else
  38.                               resultado[i][j]=min(resultado[i-1][j],resultado[i-1][j-1]+1,99);
  39.                            }          
  40.                        }      
  41.            }
  42.        }
  43.        int menor=99;
  44.        for (int j=0; j<columnas;j++)
  45.            if (resultado[filas-1][j]<menor)
  46.                menor=resultado[filas-1][j];
  47.        if (menor==99)
  48.            System.out.println("Yum Yum");
  49.            else System.out.println(menor);
  50. }
  51.    public static int min(int num1, int num2, int num3){
  52.        int menor=num1;
  53.        if (num2<num1)
  54.            menor=num2;
  55.        if (num3<menor)
  56.            menor=num3;
  57.        return menor;
  58.    }
  59. }