viernes, 30 de diciembre de 2011

Calcular la Enésima Potencia de un Número, en C

Este programa calcula cualquier potencia de un número entero. Recibe un par de enteros: la base y el exponente. El algoritmo es muy sencillo y se realiza todo en la función Potencia, consiste en un ciclo while que se realiza tantas veces como lo indique el exponente, la primera instrucción de ese ciclo se puede escribir como pot *= x, para hacerla un poco más eficiente.

 #include <stdio.h>
 /* stdio.h incluye entrada y salida*/
 
 int main()
 {  /*Abre main*/
  int base;
  int exponente;
  printf("\nIntroduzca la base: ");
  scanf("%d", &base);
  printf("\nIntroduzca el exponente: ");
  scanf("%d", &exponente);

  /*El llamado a la funcion Potencia se hace desde printf*/  
  printf("\n%d elevado a la %d es: %d\n", base, exponente, Potencia(base, exponente));
 return 0; 
 }  /* Cierra main*/


 ////////////////////////////////////////////////////
 // INICIA FUNCION POTENCIA
 ////////////////////////////////////////////////////

 int Potencia( int x, int y )
 {  /* Abre potencia */
 int i = 0;
 int pot = 1;

 while( i < y )
 {  // Abre while
 pot = pot*x;
 i++;
 }  // Cierra while 

 return (pot);
 }  /* Cierra potencia*/

martes, 27 de diciembre de 2011

Una Versión Limitada del Comando Unix WC

Este programa es una versión primitiva del comando wc de unix, el cual, entre otras cosas, cuenta las líneas, las palabras y los caracteres de un archivo. El cuadro siguiente muestra el resultado de ejecutar este programa con su mismo código como entrada. También se muestran los resultados que se obtienen con el comando wc.

[hernandez@localhost Programas]$ ./a.out < Programa.c

El numero de lineas es: 42
El numero de palabras es: 171
El numero de caracteres es: 1038

[hernandez@localhost Programas]$ wc Programa.c
  42  171 1038 Programa.c

Éste es el código:
 /* Este programa debe contar el numero de lineas, el numero de caracteres, palabras
    y palabras específicas.*/

 #include<stdio.h>
 #define ADENTRO 1
 #define AFUERA 0

 int main()
 {                 // Abre main
 int Caracteres = 0;
 int Palabras = 0; 
 int Lineas =  0; 
 int estado = AFUERA;
 int c;

 while ((c = getchar()) != EOF)
 /* Un error sutil dificil de detectar ocurre
    cuando se suprimen los parentesis que encierran
    la instruccion c = getchar() */
 {        // abre while
 // aqui se cuentan los caracteres
 Caracteres++;
 // Aqui se cuentan las lineas
 if ( '\n' == c )
 Lineas++;
 
 // Aqui se cuentan las palabras
 if ( (' ' == c) || ('\t' == c) || ('\n' == c) )
 estado = AFUERA;
 else
 if ( AFUERA == estado )
 {  // abre if 
 estado = ADENTRO;
 Palabras++; 
 }  // Cierra if

 }         // Cierra while

 printf("\n\nEl numero de lineas es: %d", Lineas);
 printf("\nEl numero de palabras es: %d", Palabras);
 printf("\nEl numero de caracteres es: %d\n\n", Caracteres);
 
 }                 // Cierra main

Búsqueda de un Carácter en un Archivo, en C

El siguiente programa recibe un texto y busca e imprime en qué línea y posición se encuentra un caracter dado. En este caso el programa busca la letra 'd', pero se puede cambiar para buscar cualquier caracter. El programa es muy sencillo, pero es un primer paso para hacer una búsqueda de una cadena. El siguiente es el resultado de ejecutar el programa con su mismo código como entrada.

 #include<stdio.h>
           
 int main()
 {  // Abre main
 int c, lineas = 1;
 int posicion = 0;
 int s = 'd'; // cambiar q por cualquier
              // caracter   
 while ((c = getchar()) != EOF)
 {   // abre while
    
 if ( '\n' != c )
 { // Abre if
 posicion++;
 if (s == c )
 {
 printf("\nEl caracter ");
 putchar(c);
 printf(" aparece en la posicion: %d de la linea %d", posicion, lineas);  
 }
 }  // Cierra if
 else
 {  // Abre else
 lineas++;
 posicion = 0;  
 }  // Cierra else
 }   // Cierra while 
 printf("\n");
 }   // Cierra main

domingo, 27 de noviembre de 2011

Paso de Estructuras a Funciones en C++

Para pasar datos tipo struct a funciones en C++ es posible hacerlo de dos diferentes maneras:

1) Invocando la función con el nombre del tipo creado como struct. La función invocada recibe la dirección de la estructura y usa un alias para referirse a ella.

2) Invocando la función con el nombre del tipo creado como struct. La función invocada recibe como parámetro un dato del tipo creado como struct.

Pasar estructuras a funciones es muy parecido a pasar un arreglo.

En el siguiente ejemplo se usan los dos casos mencionados.

 #include <iostream>
 using namespace::std;

 struct Datos
 {
 // Estos datos no se pueden 
 // inicializar
 int anio;
 int mes;
 int dia;
 };

 // Prototipos de funcion
 void Recibe( Datos &s);
 void Imprime1( Datos &t);
 void Imprime2( Datos Nacimiento);

 /////////////////////////////////////////////////////////////
 // MAIN
 /////////////////////////////////////////////////////////////

 int main()
 {      // Abre main
 // Declaracion de Elisa como tipo Datos
 Datos Elisa;

 // Se reciben los datos de Elisa mediante la funcion Recibe
 Recibe(Elisa);

 // Se imprimen los datos de Elisa desde la funcion Imprime1
 cout <<"\nLa fecha de nacimiento de Elisa desde Imprime1: "<<endl;
 Imprime1(Elisa);
 // Se imprimen los datos de Elisa desde la funcion Imprime2
 cout <<"\nLa fecha de nacimiento de Elisa desde Imprime2:" <<endl;
 Imprime2(Elisa);
 // Se imprimen los datos de Elisa desde main 
 cout <<"\nLa fecha de nacimiento de Elisa desde main." <<endl;
 cout <<Elisa.dia<<"/" <<Elisa.mes<< "/" << Elisa.anio << endl << endl; 

 return 0;
 }      // Cierra main

 /////////////////////////////////////////////////////////////////
 // RECIBE
 ////////////////////////////////////////////////////////////////

 void Recibe( Datos &s)
 {      // Abre funcion Recibe
 cout << "\nIntroduzca el anio de nacimiento: " <<endl;
 cin >> s.anio;
 cout << "\nIntroduzca el mes de nacimiento: " <<endl;
 cin >> s.mes;
 cout <<"\nIntroduzca el dia de nacimiento: " <<endl; 
 cin >> s.dia;
 }      // Cierra funcion Recibe

 ////////////////////////////////////////////////////////////////
 // IMPRIME1
 ////////////////////////////////////////////////////////////////

 void Imprime1( Datos &t)

 {    // Abre Imprime
 cout <<t.dia <<"/"<<t.mes<<"/"<<t.anio<<endl;
 return;
 }    // Cierra Imprime

 ////////////////////////////////////////////////////////////////
 // IMPRIME2
 ////////////////////////////////////////////////////////////////

 void Imprime2( Datos Nacimiento)
 { // Abre 
 cout << Nacimiento.dia <<"/" <<Nacimiento.mes<<"/"<< Nacimiento.anio << endl;
 return;
 }


Una ejecución de este programa es la siguiente:

lunes, 21 de noviembre de 2011

Barajado de Cartas en Java

Este programa es parte del libro Java Cómo Programar, Séptima edición, de Deitel. Algunos de los problemas propuestos más complicados del capítulo 7 tienen que ver con la modificación de éste código. Por eso lo incluyo aquí como una referencia. Lo que hace es solamente barajar todas las cartas, como puede verse ejecutando este programa.

El siguiente código debe guardarse con el nombre PruebaPaqueteDeCartas.java

public class PruebaPaqueteDeCartas
 {     // Abre clase PruebaDeCartas

 public static void main(String args[])
 {     // Abre main
  PaqueteDeCartas miPaqueteDeCartas = new PaqueteDeCartas();
  miPaqueteDeCartas.barajar();
  
  ///////////////////////////////////
  // IMPRIME
  //////////////////////////////////

 System.out.println("\n");
 for ( int i = 0; i < 13; i++ )
 { // Abre for
 System.out.printf("%-20s%-20s%-20s%-20s\n", 
 miPaqueteDeCartas.repartirCarta(), miPaqueteDeCartas.repartirCarta(),
 miPaqueteDeCartas.repartirCarta(), miPaqueteDeCartas.repartirCarta());
 }  // Cierra for

 System.out.println("\n");
 }     // Cierra main
 }     // Cierra clase PruebaDeCartas

El siguiente código debe guardarse con el nombre Carta.java

public class Carta
 
 { // Abre clase Carta

 private String cara;
 private String palo;
 public Carta( String caraCarta, String paloCarta)
 {   // Abre constructor
 cara = caraCarta;
 palo = paloCarta;

 }   // Cierra constructor

 public String toString()
 {   // Abre metodo toString
 return cara + " de " + palo;
 }   // Cierra metodo toString
 } // Cierra clase Carta


El siguiente código debe guardarse con el nombre PaqueteDeCartas.java

import java.util.Random;

 public class PaqueteDeCartas

 {  // Abre clase PaqueteDeCartas
 private Carta paquete[];
 private int cartaActual;
 private final int NUMERO_DE_CARTAS = 52;
 private Random numerosAleatorios;

 /////////////////////////////////////////////////////////////////
 // CONSTRUCTOR
 /////////////////////////////////////////////////////////////////

 public PaqueteDeCartas()
 {   // ABre constructor PaqueteDeCartas

 String caras[] = { "AS", "DOS", "TRES", "CUATRO", "CINCO", "SEIS", "SIETE",
 "OCHO", "NUEVE", "DIEZ", "JOTO", "QUINA", "REY"};
 String palos[] = { "CORAZONES", "DIAMANTES", "TREBOLES", "ESPADAS"};

 paquete = new Carta[ NUMERO_DE_CARTAS ];
 cartaActual = 0;
 numerosAleatorios = new Random();

 for ( int cuenta = 0; cuenta < paquete.length; cuenta++ )
 paquete[ cuenta ] = new Carta( caras[cuenta % 13], palos[cuenta/13]); 
 }   // Cierra constructor PaqueteDeCartas


 /////////////////////////////////////////////////////////////////
 // METODO BARAJAR
 /////////////////////////////////////////////////////////////////

 public void barajar()
 {   // Abre metodo barajar
 cartaActual = 0;
 
 for ( int primera = 0; primera < paquete.length; primera++ )
 { // Abre for
 int segunda = numerosAleatorios.nextInt(NUMERO_DE_CARTAS);
 
 Carta temp = paquete[primera];

 paquete[primera] = paquete[segunda];
 paquete[segunda] = temp;
 
 }  // Cierra for
 }   // Cierra metodo barajar 

 public Carta repartirCarta()
 {  // Abre metodo repartirCarta
 if (cartaActual < paquete.length )
 return paquete[cartaActual++];
 else return null;
 }  // Cierra metodo repartirCarta
 }  // Cierra clase PaqueteDeCartas

domingo, 20 de noviembre de 2011

Determinar si un año es bisiesto en C++

Este programa es parte del libro Programación y Resolución de Problemas con C++ de Nell Dale y Cheep Weems, cuarta edición. El problemita es sencillo pero sirve, al menos para mí, como un primer uso del tipo de datos boolean. Para entender el algoritmo basta con recordar que un año bisiesto es aquel que tiene 366 dias en vez de 365. La regla, en el calendario gregoriano, es la siguiente:

Un año es bisiesto si es divisible entre 4, excepto el último de cada siglo (aquel divisible por 100), salvo que este último sea divisible por 400.

Con ésto es posible escribir la función Bisiesto que contiene este programa. Tal vez lo único extraño es la llamada de esta función mediante if. En realidad hay que recordar que un condicional en C++ se evalúa como true o como false, (véase el inciso 3 de esta entrada)así que, dado que la función llamada (Bisiesto) devuelve uno de esos dos valores, es perfectamente válido invocarla en el if.

////////////////////////////////////////////////////
 // Este programa recibe un anio e imprime si es   //
 // bisiesto o no                                  // 
 // /////////////////////////////////////////////////
 

 #include <iostream>
 using namespace::std;

 bool Bisiesto( int );

 int main()
 {                //  Abre main
 int anio;
 cout <<"\nIntroduzca un anio y sabra si es bisiesto:\n";
 cin >> anio;

 if ( Bisiesto( anio ) )
 // Nota: If solo evalua true o false
 cout << anio << " es un anio bisiesto." << endl;
 else // es decir, si es false
 cout << anio << " no es un anio bisiesto." << endl;
 
 return 0;
 }                // Cierra main

 ////////////////////////////////////////////////////
 // FUNCION BISIESTO
 ////////////////////////////////////////////////////
 
 bool Bisiesto( int a  )
 // Esta funcion regresa un valor booleano true
 // si el anio es bisiesto y regresa el valor 
 // booleano false si el anio no es bisiesto

 {     // Abre funcion Bisiesto

 if ( 0 != a%4 )
 return false;
 else if ( 0 != a % 100 )
 return true;
 else if ( 0 != a % 400 )
 return false;
 else 
 return true;
 }     // Cierra funcion Bisiesto
Aquí una ejecución del programa:

Introduzca un anio y sabra si es bisiesto:
2004
2004 es un anio bisiesto.



lunes, 14 de noviembre de 2011

Deitel_Java_7.21 (Lenguaje Logo en Java)


Saludo en Logo
7.21 (Gráficos de Tortuga) El lenguaje logo hizo famoso el concepto de los gráficos de tortuga. Imagine a una tortuga mecánica que camina por todo el cuarto, bajo el control de una aplicación en Java. La tortuga sostiene una pluma en una de dos posiciones, arriba o abajo. Mientras la pluma está abajo, la tortuga va trazando figuras a medida que se va moviendo, y mientras la pluma está arriba, la tortuga se mueve alrededor libremente sin trazar nada. En este problema usted simula la operación de la tortuga y creará un blog de dibujo computarizado.
Utilice un arreglo de 20 por 30 llamado piso que se inicialice con ceros. Lea los comandos de un arreglo que los contenga. Lleve el registro de la posición actual de la tortuga en todo momento, y si la pluma se encuentra arriba o abajo. Suponga que la tortuga siempre empieza en la posición (0,0) del piso con su pluma hacia arriba. El conjunto de comandos de la tortuga que su aplicación debe procesar se muestra a continuación.

1 Pluma arriba
2 Pluma abajo.
3 Gira a la derecha.
4 Gira a la izquierda.
5 Avanza.
6 Imprime el arreglo.
9 Centinela (Fin de datos)
_____________________________________________________________________________________
SOLUCIÓN:
Este programa también aparece resuelto en C++ en este blog. Esta versión en Java me ha resultado más fácil de escribir. Es posible añadir más comandos y hacer este código más interesante. Como consejo si lo que quiere es escribir este código, lo primero que debe hacerse es asegurarse que la tortuga gira correctamente hacia la derecha y hacia la izquierda. Para esto es necesario saber cual es la dirección de la tortuga, esto lo hace el método Dirección. He usado las letras k, l, j, h para referirme a "arriba", "derecha", "abajo" y "izquierda" respectivamente, porque esas son las teclas de desplazamiento del editor Vi. Una vez que la tortuga gira correctamente es necesario hacerla avanzar y retroceder en líneas horizontales, y después en verticales. Finalmente he agregado la opción imprimir comando para que el usuario sepa en todo momento qué se espera de él.

Este código debe guardarse con el nombre UsaLogo.java

public class UsaLogo
 {            // Abre clase Logo
 
 public static void main(String args[])
 {     // Abre main
 Logo miObjeto = new Logo();
 miObjeto.Administrador_Logo();
 }      // Cierra main
 }            // Cierra clase Logo


Este código debe guardarse con el nombre Logo.java

import java.util.Scanner;

 public class Logo
 {   // Abre clase Logo
 Scanner entrada = new Scanner(System.in);
 private int Direccion = 'l';
 private int Pluma = 1; // La pluma inicia hacia arriba
 private int ANCHO_TABLERO = 90;
 private int ALTO_TABLERO = 40;
 private int Tablero[][] = new int[ALTO_TABLERO + 1][ANCHO_TABLERO + 1];
 private int X = 1;  // La tortuga inicia en la parte superior
 private int Y = 1;  // izquierda
 

 public void Administrador_Logo()
 {       // Abre metodo Administrdor_Logo

 int comando;

 
 System.out.println("\nPor favor introduzca comando: ");
 comando = entrada.nextInt();

 while ( 0 != comando )
 {      // Abre while 
 switch (comando)
 {   // Abre switch
 case 1:
 System.out.println("\nLa pluma esta hacia arriba.");
 Pluma = 1;
 break;
 case 2:
 System.out.println("\nLa pluma esta hacia abajo.");
 Pluma = 2;
 break;

 case 3:
 System.out.println("\nSe gira a la derecha.");
 switch (Direccion)
 {  // Abre switch anidado
 case 'k':
 Direccion = 'l';
 break;
 case 'l':
 Direccion = 'j';
 break;
 case 'j':
 Direccion = 'h';
 break;
 case 'h':
 Direccion = 'k';
 break;
 default:
 System.out.println("\nDireccion Invalida");
 break; 
 }  // Cierra switch anidado
 break;

 case 4:
 System.out.println("\nSe gira a la izquierda");
 switch (Direccion)
 {     // Abre switch
 case 'k':
 Direccion = 'h';
 break;
 case 'h':
 Direccion = 'j';
 break;
 case 'j':
 Direccion = 'l';
 break;
 case 'l':
 Direccion = 'k';
 break;
 default:
 System.out.println("\nDireccion invalida.");
 break;
 }     // Cierra switch
 break;

 case 5:
 Avanza();
 break;
 case 6:
 Imprimir_Tablero();
 break;
 case 7:
 System.out.printf("\nLa direccion de la tortuga es: %c", Direccion);
 System.out.printf("\nLa posicion de la tortuga es X = %d, Y = %d\n", X, Y);
 break;
 case 8:
 System.out.println("\nLos comandos son:");
 Imprimir_Comandos();
 break;

 default:
 System.out.println("\nComando invalido.\n");
 break;
  
 }   // Cierra switch
 System.out.print("\nPor favor introduzca comando, 0 para terminar, ");
 System.out.print("8 para imprimir los comandos.\n");
 comando = entrada.nextInt();
 
 }      // Cierra while
 }       // Cierra metodo Administrador_Logo

 ////////////////////////////////////////////////
 // METODO AVANZA
 ///////////////////////////////////////////////
 
 public void Avanza()
 {        // Abre metodo Avanza
 int casillas_avanza;
 System.out.println("\nPor favor introduzca las posiciones que avanzara la tortuga: ");
 casillas_avanza = entrada.nextInt();
 switch (Direccion)
 {     // Abre switch
 case 'l':
 
 if ( X + casillas_avanza <= ANCHO_TABLERO)
 
 { // Abre if 
 if ( 1 != Pluma) // Si la pluma esta hacia abajo
 for ( int i = X; i <= X + casillas_avanza; i++ )
 Tablero[Y][i] = 1; 

 // El cambio en X se hace al final 
 // para no afectar a la variable que de hecho aparece
 // en el ciclo for anterior
 X += casillas_avanza;
 
 }  // Cierra if
 else
 {  // Abre else
 if ( 1 != Pluma )
 for ( int j = X; j <= ANCHO_TABLERO; j++ )
 Tablero[Y][j] = 1;
 X = ANCHO_TABLERO;
 // De nuevo, el cambio en X se hace al final, de lo contrario
 // Se alteraria la misma variable que aparece en el diclo for
 }  // Cierra else
 break;

 case 'h':
 if ( 1 <= X - casillas_avanza )
 {  // Abre if
 if ( 1 != Pluma )
 for ( int i = X; i >= X - casillas_avanza; i--)
 {  // Abre for
 Tablero[Y][i] = 1; 
 }  // Cierra for
 
 X -= casillas_avanza;
 }  // Cierra if 
 else  // es decir, si X - casillas_avanza < 1
 {    // Abre else
 if ( 1 != Pluma )
 for ( int i = X; i >= 1; i--)
 Tablero[Y][i] = 1;

 X = 1; 
 }    // Cierra else
 break;

 case 'j':
 if ( Y + casillas_avanza <= ALTO_TABLERO)
 
 { // Abre if 
 if ( 1 != Pluma) // Si la pluma esta hacia abajo
 for ( int i = Y; i <= Y + casillas_avanza; i++ )
 Tablero[i][X] = 1; 

 // El cambio en Y se hace al final 
 // para no afectar a la variable que de hecho aparece
 // en el ciclo for anterior
 Y += casillas_avanza;
 
 }  // Cierra if
 else
 {  // Abre else
 if ( 1 != Pluma )
 for ( int j = Y; j <= ALTO_TABLERO; j++ )
 Tablero[j][X] = 1;
 Y = ALTO_TABLERO;
 // De nuevo, el cambio en X se hace al final, de lo contrario
 // Se alteraria la misma variable que aparece en el diclo for
 }  // Cierra else
 break;
 
 case 'k':

 if ( 1 <= Y - casillas_avanza )
 {  // Abre if
 if ( 1 != Pluma )
 for ( int i = Y; i >= Y - casillas_avanza; i--)
 {  // Abre for
 Tablero[i][X] = 1; 
 }  // Cierra for
 
 Y -= casillas_avanza;
 }  // Cierra if 
 else  // es decir, si X - casillas_avanza < 1
 {    // Abre else
 if ( 1 != Pluma )
 for ( int i = Y; i >= 1; i--)
 Tablero[i][X] = 1;

 Y = 1; 
 }    // Cierra else
 break;

 default:
 System.out.println("\nDireccion equivocada.");
 break; 
 }    // Cierra switch  
 }        // Cierra metodo Avanza 

 ///////////////////////////////////////////////
 // IMPRIMIR_TABLERO 
 ///////////////////////////////////////////////

 public void Imprimir_Tablero()
 {    // Abre metodo Imprimir_Tablero

 System.out.printf("\nEl Tablero es de %d de ancho X %d de alto\n", ANCHO_TABLERO, ALTO_TABLERO);
 // Imprime contorno superior del tablero
 System.out.printf("|");
 for ( int n = 1; n <= ANCHO_TABLERO; n++ )
 System.out.printf("-");

 System.out.printf("|\n");
 // Imprime el tablero
 for ( int i = 1; i <= ALTO_TABLERO; i++ )
 {   // Abre for
 // Escribe contorno derecho
 System.out.printf("|");
 // Imprime renglon
 for ( int j = 1; j <= ANCHO_TABLERO; j++ )
 {  // Abre for anidado
 if ( 0 == Tablero[i][j])
 System.out.printf(" ");
 else
 System.out.printf("*");
 }      // Cierra for anidado
 System.out.printf("|%d\n", i);
 }  // Cierra for 

 // Imprime contorno inferior del tablero
 System.out.printf("|");
 for ( int m = 1; m <= ANCHO_TABLERO; m++ )
 System.out.printf("-");
 System.out.printf("|");
 
 
 }    // Cierra metodo Imprimir_Tablero

 ///////////////////////////////////////////////
 // METODO IMPRIMIR_COMANDOS
 ///////////////////////////////////////////////

 public void Imprimir_Comandos()
 {     // Abre metodo Imprimir_Comandos
 System.out.println("\n1 Pluma hacia arriba.");
 System.out.println("2 Pluma hacia abajo.");
 System.out.println("3 Gira a la derecha.");
 System.out.println("4 Gira a la izquierda.");
 System.out.println("5 Avanza.");
 System.out.println("6 Imprime Tablero.");
 System.out.println("7 Imprime Posicion y Direccion.");
 System.out.println("8 Imprime comandos.");
 }     // Cierra metodo Imprimir_Comandos

 
 }   // Cierra clase Logo

lunes, 31 de octubre de 2011

Deitel_Java_7_25 (Ocho Reinas: Método de Fuerza Bruta)

Una solución al problema de las Ocho Reinas
7.25 (Ocho reinas: método de fuerza bruta) En este ejercicio usted desarrollará varios métodos de fuerza bruta para resolver el problema de las Ocho Reinas que presentamos en el ejercicio 7.24
a) Utilice la técnica de fuerza bruta aleatoria desarrollada en el ejercicio 7.23, para resolver el problema de las Ocho Reinas.
b)Utilice una técnica exhaustiva (es decir, pruebe todas las combinaciones posibles de las ocho reinas en el tablero para resolver el problema de las Ocho Reinas.
c) Por qué el método de la fuerza bruta exhaustiva podría no ser apropiado para resolver el problema del paseo del caballo?
d) Compare y contraste el problema de la fuerza bruta aleatoria con el de la fuerza bruta exhaustiva.
El problema de las N reinas, un caso particular.
Solución
El enfoque de este problema es parecido al circuito del caballo por medio de la fuerza bruta

El método es bastante simple y el código tiene como 150 líneas. En los comentarios se presenta el seudocódigo, que es bastante fácil de seguir. Cambiando un par de variables, indicadas en el programa, se puede de manera sencilla hacer que este programa resuelva el problema de las n reinas en un tablero de nxn. En la imagen lateral puede verse el caso de un tablero de 5x5.

Este código debe guardarse con el nombre de UsaOchoReinas.java

public class UsaOchoReinas

{  // Abre UsaOchoReinas
public static void main(String args[])
{        // Abre main
Ocho_Reinas miObjeto = new Ocho_Reinas();
miObjeto.Principal(); 
}        // Cierra main
}  // Cierra UsaOchoReinas


Este código debe guardarse con el nombre de Ocho_Reinas.java

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

       PROBLEMA DE LAS 8 (EN REALIDAD N) REINAS CON EL METODO DE FUERZA BRUTA
      
 ***********************************************************************************/

 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                              ALGORITMO                                          *
 * Mientras                                                                        *
 *              (contador_reinas < Numero solicitado de reinas)                    *
 *                                  &&                                             *              
 *                  Intentos fallidos < numero grande de fracasos                  *
 *                                                                                 *
 *Elegir aleatoriamente una casilla                                                *
 *                                                                                 *
 * verificar que la casilla este libre (no se haya colocado una reina ahi)         *
 *                                                                                 *
 * <Si la casilla ocupada>                                                         *
 *   incrementa el numero de fracasos                                              *
 *   elige otra casilla aleatoriamente                                             *
 *   y repite el proceso                                                           *
 *                                                                                 *
 * <Si la casilla no esta ocupada>                                                 *
 *  Verifica que la casilla no este atacada                                        * 
 * <Si la casilla esta atacada>                                                    *
 * (Esto se hace revisando que la columna y la fila de la casilla elegida no       *
 *  coincida con ninguna de las respectivas filas y columnas de las reinas ya      *
 *  colocadas, y que la distancia entre dicha fila y la de cualquier reina ya      *
 *  colocada no sea igual a la distancia entre la columna elegida y la columna     *
 *  de cualquier reina ya colocada                *                                *
 *  En otras palabras, si dos reinas se atacan en diagonal, forman un triangulo    *
 *  rectangulo isosceles)                                                          *
 *  igual que la distancia                                                         *
 *  incrementa el numero de fracasos                                               *
 *  elige otra casilla aleatoriamente                                              *
 *  y repite el proceso                                                            *
 * <Si la casilla no esta atacada>                                                 *
 *  coloca la reina ahi (en realidad el numero de contador_reinas ) y              *
 *  aumenta en uno el contador_reinas                                              *
 *                                                                                 *
 * OBSERVACION: Este algoritmo funciona para el problema de las n reinas en un     *
 * tablero de nxn                                                                  *
 *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
 import java.util.Scanner;
 import java.util.Random;

 public class Ocho_Reinas

 {        // Abre clase Ocho_Reinas
 Scanner entrada = new Scanner(System.in);
 Random aleatorio = new Random();
 private int Tamano;
 // Cambiar la variable Tamano para resolver el problema de las
 // n reinas
 private int Fracasos_Requeridos = 1000;
 // Cambiar tambien esta variable ajustandola segun un buen criterio
 // para un Tamano grande
 private int dado1;
 private int dado2;
 private int contador_reinas = 0;

 ///////////////////////////////////////////////////////////
 // Metodo Principal
 ///////////////////////////////////////////////////////////

 public void Principal()
 {    // Abre metodo Principal
 int accesibilidad;

 System.out.println("\nEste programa resuelve el problema de las ocho reinas.");
 System.out.print("\nPor favor introduzca el numero de casillas del tablero.\n");
 Tamano = entrada.nextInt();
 int fracasos = 0;
 int A[][] = new int[Tamano + 1][Tamano + 1];

 while ( Tamano > contador_reinas && fracasos < Fracasos_Requeridos)
 {
 Genera_Casilla(); 
 accesibilidad =  Verifica_Posicion(A);
 if ( 0 == accesibilidad )
 fracasos++;
 else
 A[dado1][dado2] = ++contador_reinas;
 }

 if ( Tamano != contador_reinas)
 System.out.printf("\nLo siento. Solo se colocaron %d reinas\n", contador_reinas);
 else
 System.out.printf("\nSE COLOCARON LAS %d REINAS!\n", Tamano);

 // Se invoca al metodo Imprime
 Imprime(A);

 }    // Cierra metodo Principal

 ///////////////////////////////////////////////////////////////
 // Metodo Genera_Casilla
 ///////////////////////////////////////////////////////////////
 
 public void Genera_Casilla()
 {         // Abre metodo Genera_Casilla
 dado1 = aleatorio.nextInt(Tamano) + 1;
 dado2 = aleatorio.nextInt(Tamano) + 1;
 }        // Cierra metodo Genera_Casilla

 ////////////////////////////////////////////////////////////
 // Metodo Verifica_Posicion
 ////////////////////////////////////////////////////////////  

 public int Verifica_Posicion(int B[][] )
 {         // Abre metodo Verifica_Posicion
 int estatus = 1;
 // Al principio se supone que la casilla es valida
 // y se descartara en el siguiente if si no cumple
 // con ciertas condiciones

 if ( 0 == B[dado1][dado2] )
 // Si la casilla generada esta vacia
 {          // Abre if  
 for ( int i = 1; i <= Tamano; i++ )
 for ( int j = 1; j <= Tamano; j++ )
 {  // Abre for
 // Si la casilla tiene una reina
 if ( 0 != B[i][j] )
 {       // Abre if
 // Si la reina ataca la misma fila o columna
 if ((( dado1 == i) || (dado2 == j ))  || (Math.abs(dado1 - i) == Math.abs(dado2 - j )) )
 // Retorna Negativo
 {
 estatus = 0;
 break;
 }
 }       // Cierra if 
 }   // Cierra for  

 }       // Cierra if
 else
 // Si la casilla generada no esta vacia, evidentemente
 // no es viable
 estatus = 0;

 return estatus;
 // Se retorna el estatus de la casilla
 // 1: valida, 0: invalida
 }         // Cierra metodo Verifica_Posicion

 /////////////////////////////////////////////////////////////
 // Metodo Imprime
 /////////////////////////////////////////////////////////////

 public void Imprime(int C[][])
 {      // Abre Imprime

 for ( int k = 1; k <= Tamano; k++ )
 {
 for ( int j = 1; j <= Tamano; j++)
 {
 System.out.printf("%5d", C[k][j]);
 } 
 System.out.println("\n");
 }
 }     // Cierra imprime

} // Cierra clase Ocho_Reinas

martes, 25 de octubre de 2011

Deitel_Java_7.23 a) ( Circuito del Caballo en Java, Método de Fuerza Bruta)

Una solución al recorrido del caballo

7.23 (Paseo del Caballo: Métodos de Fuerza Bruta) En la parte c del ejercicio 7.22 desarrollamos una solución al problema del paseo del caballo. El método utilizado, llamado "heurística de accesibilidad", genera muchas soluciones y se ejecuta con eficiencia. A medida que se incremente de manera continua la potencia de las computadoras, seremos capaces de resolver más problemas con menos potencia y algoritmos relativamente menos sofisticados. A éste le podemos llamar el método de la "fuerza bruta" para resolver problemas.

a) Utilice la generación de números aleatorios para permitir que el caballo se desplace a lo largo del tablero (mediante sus movimientos legítimos en L) en forma aleatoria. Su aplicación debe ejecutar un paseo e imprimir el tablero final. ¿Qué tan lejos llegó el caballo?
_____________________________________________________________________________________
SOLUCIÓN:
En este programa el caballo llega tan lejos como el usuario quiera. Se ha puesto un ciclo while que corre el algoritmo tantas veces como sean necesarias para que se obtengan las casillas deseadas. En los comentarios del programa viene bien explicado de qué se trata. Pero debo decir que este algoritmo es bastante simple. La clase Caballo, que es la que hace el trabajo, tiene, con comentarios, 176 líneas de código. He visto soluciones más complicadas, y yo mismo tengo en este blog unas muy rebuscadas. La idea es muy sencilla. El caballo empieza en una casilla la (1,1) en este caso pero puede ser cualquiera, a partir de ahí ¿a dónde mover? Ya que el problema va a ser resuelto mediante la fuerza bruta suponemos que un mono lanza un par de dados que tienen caras del 1 al 8. El primero de ellos decide la linea y el siguiente la columna. Si antes no ha pasado el caballo por ahí, lo cual se indica con un numero, entonces el mono procede a medir la distancia entre la posicion actual en x y la coordenada x de la casilla, si es 1 o 2 se analiza la distancia en y, la cual debe ser 2 o 1, respectivamente. Si se cumplen estas condiciones entonces se escribe el número de casillas que lleva recorridas el caballo y se sigue adelante. El caballo puede llegar a un punto muerto. Si después de un cierto número de lanzamientos de dados (1000 en este programa) no se ha incrementado el número de casillas recorridas, entonces se deja de intentar. El programa pregunta cuántas casillas quiere que recorra el caballo. Es bueno iniciar con pocas, pero en realidad la única que tarda un poco ( unos cinco minutos en promedio en mi máquina bastante vieja ) es 64. El recorrido de la figura fue obtenido en unos dos minutos aproximadamente.
Más importante aún, con cambiar 8 por cualquier otro número se puede encontrar recorridos para tableros de nxn y resolver el problema general. En teoría de grafos este problema consiste en encontrar el circuito de Hamilton, aquel que pasa por todas las aristas del grafo.

Este código debe guardarse con el nombre UsaCaballo.java

public class UsaCaballo

{  // Abre  UsaCaballo

public static void main(String args[])
{     // Abre main
Caballo miObjeto = new Caballo();
miObjeto.Recibe();
}     // Cierra main

}  // Cierra UsaCaballo

El siguiente código debe guardarse con el nombre Caballo.java

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  *                                                                        *
  *                                                                        *
  *                            DEITEL 7.23 a)                              *
  *                                                                        *
  *  Este programa intenta el recorrido del caballo en un tablero de       *
  *  ajedrez mediante la fuerza bruta.                                     *
  *                                                                        *
  *                                                                        *
  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

  /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   *                                                                       *
   *                               ALGORITMO:                              * 
   *                               __________                              *
   *                                                                       * 
   *  La idea de este algorimo es bastante simple:                         *
   *                                                                       *
   * PASO 1: El tablero de ajedrez (arreglo de 8x8) se llena con 0 en todas*
   * las entradas exepto en la esquina superior derecha, que se coloca un 1*
   * De ahi es de donde parte el caballo.                                  *
   *                                                                       *  
   * PASO 2: Se lanza un par de "dados" de ocho caras El primer dado decide*
   * el renglon, el siguiente decide la columna.                           *
   *                                                                       *
   *PASO 3: Es necesario verificar que el caballo no haya pasado antes por *
   *ahi, o que la casilla seleccionada tenga un 0 Si no es asi se repite el*
   *Paso2. Si efectivamente es un 0, entonces se verifica que la casilla   *
   *elegida al azar sea "legal" o este en forma de L Para esto se verifican*
   *las distancias en X y en Y. Si el valor absoluto de la diferencia entre*
   *la casilla elegida por el dado1 y la casilla x actual es igual a 2 o  1*
   *se procede a checar el valor absoluto de la distancia entre dado2 y Y. *
   *1 para el primer caso y 2 para el segundo, indican que la casilla es   *
   *valida. Se procede a poner el numero  2 ( o 3 o 4 o el que sea)  en la *
   *casilla, lo cual indica que esa es la siguiente parada del caballo. Se *
   *incrementa la variable contador y se procede de esa manera.            * 
   *                                                                       * 
   *                                                                       *  
   *Eso es todo. Esa es la idea central. Lo demas consiste en decirle al   *
   *programa cuando ya no es posible encontrar mas casillas, y por lo      * 
   *tanto se ha llegado a un rincon sin salida. Para eso se introduce una  *
   *variable que cuenta el numero de veces que se ha lanzado los dos dados *
   *sin cambiar de casilla.  Si se cumplen estos el programa entiende que  *
   *no hay salida y deja de intentar buscarla. Esto significa que 15 de    *
   *cada 1000 veces dejara de intentar cuando en realidad hay una casilla  *
   *a la cual mover. Se puede cambiar y poner un limite mas grande, pero   *
   *como he puesto un ciclo mas grande afuera que permite al usuario pedir *
   *una cuota minima de recorrido, hacerlo significa mas tiempo.           *
   *                                                                       *
   *                                                                       *
   *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

import java.util.Scanner;
import java.util.Random;

public class Caballo
{  // Abre clase Caballo
private int x = 1;  // El caballo inicia en la casilla superior izquierda
private int y = 1;
private int tamano = 8; // El arreglo es de ocho x ocho
private int contador = 1; // Esta variable lleva la cuenta de las casillas
                           // recorridas
int ciclos = 0;           // Esta variable cuenta los ciclos que se inten
                           // tan antes de determinar que ya no hay lugares
                           // a los cuales ir                            
int intentos_fallidos = 0; // Esta variable cuenta cuantos ciclos se inte
  //tan antes de obtener el que pidio el usuario para 64 pueden ser varios
  // millones

Scanner entrada = new Scanner(System.in);
 
public void Recibe() 
{  // Abre Recibe
Random aleatorio = new Random();

int Arreglo[][] = new int[tamano + 1][tamano +1];
// Se define el arreglo de 9*9 para evitar el 0 
Arreglo[1][1] = 1;
int dado1;
int dado2;
int casillas_requeridas = 0;
  
System.out.println("\nCuantas casillas quiere que recorra por lo menos?");
System.out.printf("\nAdvertencia: Si pide mas de %d el programa no terminara nunca:\n", tamano*tamano);
  casillas_requeridas = entrada.nextInt();
  
// Debido a que se usara la fuerza bruta de la computacion para encontrar un
// recorrido completo se anade este while

while ( contador < casillas_requeridas )
{
intentos_fallidos++;  // Se incrementa cada que inicia un intento
contador = 1;    // Dado que ya se ha colocado al caballo en (1,1), se  
                   // inicia el contador en 1
int ciclos = 0;   // Se inicia con 0 ciclos o lanzamientos de dados infructuosos 
// Cada vez que se aborta un intento han de limipiarse las casillas, con el siguiente
//par de ciclos se establecen a 0 nuevamente.

for ( int s = 0; s <= tamano; s++ )
{       // Abre for
for ( int t = 0; t <= tamano; t++ )
Arreglo[s][t] = 0; 
}       // cierra for 
 
//Se ha de colocar el caballo en la esquina superior izquierda cada vez
// desde luego se puede poner en cualquier parte
x = 1;
y = 1;
 
Arreglo[1][1] = 1;
// Mientras no se encuentre un lugar para poner al caballo

while ( 1000 != ciclos)
// Este ciclo while basicamente hace el PASO 3 del algoritmo
{  // Abre while
ciclos++;
dado1 = 1 + aleatorio.nextInt(8);
dado2 = 1 + aleatorio.nextInt(8);

if ( Math.abs(Math.abs(x) - Math.abs(dado1)) == 2) 
{ // Abre if
if ( Math.abs(Math.abs(y) - Math.abs(dado2)) == 1  )
 
if ( 0 == Arreglo[dado1][dado2])
{   // Abre if
Arreglo[dado1][dado2] = ++contador;   
x = dado1;
y = dado2;
ciclos = 0;
}  // Cierra if 
}  //Cierra if 

 
if ( Math.abs(Math.abs(x) - Math.abs(dado1)) == 1) 
{  // abre if
if ( Math.abs(Math.abs(y) - Math.abs(dado2)) == 2  )
if ( 0 == Arreglo[dado1][dado2] )
{    // Abre if 
Arreglo[dado1][dado2] = ++contador; 
x = dado1;
y = dado2;
ciclos = 0;
}  // Cierra if
}  // Cierra if
 
}  // Cierra while anidado
}    // Cierra while

System.out.println("\nLISTO!");
System.out.printf("\nSe recorrieron %d casillas.\n", contador);
System.out.printf("\nSe intentaron %d circuitos antes de obtener el requerido.\n", intentos_fallidos); 
Imprime( Arreglo );

}   // Cierra Recibe

/*El metodo siguiente despliega el tablero de ajedrez */

//////////////////////////////////////////
// Imprime
///////////////////////////////////////////
 
public void Imprime(int B[][])
{     // Abre imprime
for ( int k = 1; k <= 8; k++ )
{
for ( int j = 1; j <= 8; j++)
{
System.out.printf("%5d", B[k][j]);
 
}  
System.out.println("\n");
}
}     // Cierra imprime
}    // Cierra clase Caballo

domingo, 23 de octubre de 2011

Deitel_Java_7.17 ( Lanzamiento de Dados )

El programa simula el lanzamiento de dos dados.
7.17 (Tiro de dados) Escriba una aplicación para simular el tiro de dos dados. La aplicación debe utilizar un objeto de la clase Random una vez para tirar el primer dado, y de nuevo para tirar el segundo dado. Después debe calcularse la suma de los dos valores. Cada dado puede mostrar un valor entero del 1 al 6, por lo que la suma de los valores variará del 2 al 12, siendo 7 la suma más frecuente, mientras que 2 y 12 serán las sumas menos frecuentes. Su aplicación debe tirar los dados 36 000 veces. Utilice un arreglo unidimensional para registrar el número de veces que aparezca cada una de las posibles sumas. Muestre los resultados en forma tabular. Determine si los totales son razonables (es decir, hay seis formas de tirar un siete, por lo que aproximadamente una sexta parte de los tiros deben ser 7)
Solución:
Este código debe llamarse UsaDeitel_7_17
public class UsaDeitel_7_17
 {  // Abre clase UsaDeitel_7_17
 public static void main(String args[])
 {  // Abre main
 Deitel_7_17 miObjeto = new Deitel_7_17();
  
 System.out.println("\nEste programa simula el lanzamiento de dos dados.\n");
 miObjeto.Recibir();

 }  // Cierra main
 
 }  // Cierra UsaDeitel_7_17

Este código debe guardarse como Deitel_7_17.java

import java.util.Scanner;
 import java.util.Random;
 
 public class Deitel_7_17
 {  // Abre clase Deitel_7_17

 Scanner entrada = new Scanner(System.in);
 Random aleatorio = new Random();
 private int numero;
 int Arreglo[];
 
 /////////////////////////////////////////////
 // Metodo Recibir 
 /////////////////////////////////////////////
 
 public void Recibir()
 {  // Abre metodo Recibir
 System.out.print("\nPor favor introduzca el numero de veces que se lanzaran ");
 System.out.print(" los dados\n");
 numero = entrada.nextInt();
 Arreglo = new int[numero];
 Lanzar();
 }  // cierra metodo Recibir


 /////////////////////////////////////////////
 // Metodo Lanzar
 /////////////////////////////////////////////

 public void Lanzar()
 {  // Abre metodo Lanzar
 int numero1;
 int numero2;
 
 for ( int i = 0; i < Arreglo.length; i++ )
 {      // Abre for
 numero1 = 1 + aleatorio.nextInt(6); 
 numero2 = 1 + aleatorio.nextInt(6);
 // System.out.printf("\n%d\t%d\n", numero1, numero2);
 // Descomentar para verificar que las sumas se capturan
 // de manera correcta. Para esto intruducir un numero
 // pequenio
 Arreglo[i] = numero1 + numero2; 
 }      // Cierra for 

 Contar();
 }  // Cierra metodo Lanzar

 /////////////////////////////////////////////
 // Metodo Contar
 /////////////////////////////////////////////

 public void Contar()
 {     // Abre metodo Contar
 int Contador[] = new int[13];
 
 for ( int j = 0; j < Arreglo.length; j++ )
 {  // Abre for
 for ( int k = 0; k < Contador.length; k++ )
 {      // Abre for anidado 
 if ( Arreglo[j] == k )
 Contador[k]++;
 }  // Cierra for anidado
 }  // Cierra for

 Imprimir(Contador); 

 }     // Cierra metodo Contar

 /////////////////////////////////////////////
 // Metodo Imprimir 
 /////////////////////////////////////////////

 public void Imprimir( int B[])
 { // Abre metodo Imprimir
 for (int m = 0; m < B.length; m++ )
 {       // Abre for
 System.out.printf("\n%d lanzamientos sumaron %d\n", B[m], m ); 
 }       // Cierra for
 }  // Cierra metodo Imprimir

 }  // Cierra clase Deitel_7_17

Related Posts Plugin for WordPress, Blogger...