Ejercicios Fundamentales de Programación en C

1. Selección de Oponentes en un Torneo

En un torneo de tenis de mesa, dos equipos compiten, cada uno con tres jugadores. El Equipo A está formado por Alice, Bob y Charlie, mientras que el Equipo B lo integran Xavi, Yolanda y Zoe. Se conocen las siguientes restricciones: Alice no jugará contra Xavi, y Charlie no competirá ni contra Xavi ni contra Zoe. El objetivo es determinar todas las posibles combinaciones de emparejamientos, asegurando que cada jugador del Equipo A se enfrente a un único jugador del Equipo B.

#include <stdio.h>

int main() {
    char oponenteAlice, oponenteBob, oponenteCharlie; // Representa los oponentes X, Y, Z

    printf("Posibles emparejamientos para el torneo de tenis de mesa:\n");

    // Iterar sobre las posibles asignaciones para Alice (X, Y, Z)
    for (oponenteAlice = 'X'; oponenteAlice <= 'Z'; oponenteAlice++) {
        // Iterar sobre las posibles asignaciones para Bob (X, Y, Z)
        for (oponenteBob = 'X'; oponenteBob <= 'Z'; oponenteBob++) {
            // Iterar sobre las posibles asignaciones para Charlie (X, Y, Z)
            for (oponenteCharlie = 'X'; oponenteCharlie <= 'Z'; oponenteCharlie++) {
                // Aplicar las reglas del juego y las restricciones dadas:
                // 1. Cada jugador del Equipo A debe tener un oponente único del Equipo B.
                // 2. Alice no juega contra Xavi.
                // 3. Charlie no juega contra Xavi ni contra Zoe.
                if (oponenteAlice != oponenteBob &&          // El oponente de Alice debe ser diferente al de Bob
                    oponenteAlice != oponenteCharlie &&       // El oponente de Alice debe ser diferente al de Charlie
                    oponenteBob != oponenteCharlie &&         // El oponente de Bob debe ser diferente al de Charlie
                    oponenteAlice != 'X' &&                   // Restricción: Alice no juega contra Xavi
                    oponenteCharlie != 'X' &&                 // Restricción: Charlie no juega contra Xavi
                    oponenteCharlie != 'Z') {                 // Restricción: Charlie no juega contra Zoe
                    
                    printf("Alice vs %c, Bob vs %c, Charlie vs %c\n", 
                           oponenteAlice, oponenteBob, oponenteCharlie);
                }
            }
        }
    }
    return 0;
}

2. Suma de los Dígitos de un Número Entero

Este programa solicita al usuario un número entero y luego calcula la suma de todos sus dígitos. Por ejemplo, si el usuario introduce 31421, el resultado impreso será 11.

#include <stdio.h>

int main() {
    int numeroEntrada;
    int sumaDigitos = 0;
    int digitoActual;

    printf("Por favor, ingrese un número entero: ");
    scanf("%d", &numeroEntrada);

    // Iterar mientras el número sea mayor que 0
    while (numeroEntrada > 0) {
        digitoActual = numeroEntrada % 10; // Obtener el último dígito del número
        sumaDigitos += digitoActual;       // Añadir el dígito a la suma total
        numeroEntrada /= 10;               // Eliminar el último dígito del número para la siguiente iteración
    }

    printf("La suma de los dígitos es: %d\n", sumaDigitos);
    return 0;
}

3. Verificación Sencilla de Número Primo

Este programa determina si un número entero proporcionado por el usuario es un número primo. Un número primo es un número natural mayor que 1 que no tiene divisores positivos más que 1 y él mismo.

#include <stdio.h>
#include <stdbool.h> // Para usar el tipo de dato booleano

int main() {
    int numeroUsuario;
    int divisor;
    bool esPrimo = true; // Asumimos que el número es primo hasta que se demuestre lo contrario

    printf("Ingrese un número entero para verificar si es primo: ");
    scanf("%d", &numeroUsuario);

    if (numeroUsuario <= 1) { // Los números 0, 1 y los negativos no son primos por definición
        esPrimo = false;
    } else {
        // Un número primo solo es divisible por 1 y por sí mismo.
        // Verificamos divisores desde 2 hasta numeroUsuario - 1.
        // Para optimizar, se podría verificar solo hasta la raíz cuadrada del número.
        for (divisor = 2; divisor < numeroUsuario; divisor++) {
            if (numeroUsuario % divisor == 0) {
                esPrimo = false; // Si encontramos un divisor, el número no es primo
                break;           // No necesitamos seguir buscando divisores
            }
        }
    }

    if (esPrimo) {
        printf("%d es un número primo.\n", numeroUsuario);
    } else {
        printf("%d no es un número primo.\n", numeroUsuario);
    }

    return 0;
}

4. Ordenamiento Ascendente de un Arreglo

Este ejemplo demuestra cómo ordenar un arreglo de números enteros en orden ascendente utilizando un algoritmo de ordenamiento simple (ordenamiento de burbuja).

#include <stdio.h>

int main() {
    int arregloNumeros[] = {23, 56, 24, 89, 14, 57, 95, 32};
    // Calcular el tamaño del arreglo dinámicamente
    int tamanoArreglo = sizeof(arregloNumeros) / sizeof(arregloNumeros[0]);
    int tempIntercambio; // Variable temporal para realizar intercambios

    printf("Arreglo original: ");
    for (int k = 0; k < tamanoArreglo; k++) {
        printf("%d ", arregloNumeros[k]);
    }
    printf("\n");

    // Implementación del algoritmo de ordenamiento de burbuja
    // Recorre el arreglo (tamanoArreglo - 1) veces
    for (int i = 0; i < tamanoArreglo - 1; i++) {
        // En cada pasada, el elemento más grande "burbujea" hasta su posición final
        for (int j = 0; j < tamanoArreglo - 1 - i; j++) {
            // Si el elemento actual es mayor que el siguiente, se intercambian
            if (arregloNumeros[j] > arregloNumeros[j+1]) {
                tempIntercambio = arregloNumeros[j];
                arregloNumeros[j] = arregloNumeros[j+1];
                arregloNumeros[j+1] = tempIntercambio;
            }
        }
    }

    printf("Arreglo ordenado: ");
    for (int k = 0; k < tamanoArreglo; k++) {
        printf("%d ", arregloNumeros[k]);
    }
    printf("\n");

    return 0;
}

5. Encontrar Primos Sucesivos

El objetivo es implementar una función que identifique y almacene los k primeros números primos que son estrictamente mayores que un número m dado. Estos primos se guardarán en un arreglo.

#include <stdio.h>
#include <stdbool.h> // Para el tipo booleano

// Función auxiliar para verificar si un número es primo
bool esNumeroPrimo(int num) {
    if (num <= 1) {
        return false;
    }
    // Optimización: solo necesitamos verificar divisores hasta la raíz cuadrada del número
    for (int i = 2; i * i <= num; i++) {
        if (num % i == 0) {
            return false; // Se encontró un divisor, no es primo
        }
    }
    return true; // Si no se encontraron divisores, es primo
}

// Función principal: encuentra 'cantidadPrimos' primos mayores que 'limiteInferior'
// y los almacena en el arreglo 'arrPrimos'.
void buscarPrimosConsecutivos(int limiteInferior, int cantidadPrimos, int *arrPrimos) {
    int contadorPrimosEncontrados = 0;
    int numeroActual = limiteInferior + 1; // Comenzar la búsqueda desde el número siguiente a 'limiteInferior'

    // Continuar buscando hasta que se haya encontrado la cantidad requerida de primos
    while (contadorPrimosEncontrados < cantidadPrimos) {
        if (esNumeroPrimo(numeroActual)) {
            arrPrimos[contadorPrimosEncontrados] = numeroActual;
            contadorPrimosEncontrados++;
        }
        numeroActual++; // Pasar al siguiente número para su verificación
    }
}

int main() {
    int valorM, valorK;
    int arrayPrimosAlmacenados[20]; // Un arreglo para almacenar los primos (tamaño máximo 20)

    printf("Ingrese un número límite inferior (m): ");
    scanf("%d", &valorM);
    printf("Ingrese la cantidad de primos a encontrar (k): ");
    scanf("%d", &valorK);

    // Validar que la cantidad de primos solicitada sea razonable para el tamaño del array
    if (valorK <= 0 || valorK > 20) {
        printf("La cantidad de primos (k) debe ser un número positivo y no exceder 20.\n");
        return 1; // Salir con código de error
    }

    buscarPrimosConsecutivos(valorM, valorK, arrayPrimosAlmacenados);

    printf("Los %d números primos consecutivos mayores que %d son:\n", valorK, valorM);
    for (int i = 0; i < valorK; i++) {
        printf("%d ", arrayPrimosAlmacenados[i]);
    }
    printf("\n");

    return 0;
}

6. El Problema de los Monos y los Melocotones

Un mono recolecta melocotones. Cada día, el mono come la mitad de los melocotones restantes y, adicionalmente, un melocotón más. Al inicio del décimo día, el mono descubre que solo queda un melocotón. Este programa calcula cuántos melocotones había inicialmente el primer día, utilizando tanto un enfoque iterativo como uno recursivo.

#include <stdio.h>

// Enfoque iterativo: calculando la cantidad de melocotones hacia atrás
int calcularMelocotonesIterativo(int totalDias) {
    int melocotonesDiaFinal = 1; // Sabemos que al inicio del día final (día 10) queda 1 melocotón.
    int melocotonesDiaActual = melocotonesDiaFinal;

    // Iteramos desde el día (totalDias - 1) hacia atrás hasta el día 1
    for (int dia = totalDias - 1; dia >= 1; dia--) {
        // Si 'M' melocotones quedaban al inicio del día siguiente,
        // entonces al inicio del día actual había (M + 1) * 2 melocotones.
        melocotonesDiaActual = (melocotonesDiaActual + 1) * 2;
    }
    return melocotonesDiaActual;
}

// Enfoque recursivo: la función devuelve los melocotones al inicio de un día específico.
// La base de la recursión es el día 10, donde conocemos la cantidad de melocotones.
int calcularMelocotonesRecursivo(int diaActual, int ultimoDiaConocido) {
    if (diaActual == ultimoDiaConocido) {
        return 1; // Al inicio del último día conocido (Día 10), queda 1 melocotón.
    } else {
        // La cantidad de melocotones al inicio del 'diaActual' se deriva
        // de la cantidad de melocotones al inicio del día siguiente.
        return (calcularMelocotonesRecursivo(diaActual + 1, ultimoDiaConocido) + 1) * 2;
    }
}

int main() {
    int numeroDeDias = 10;

    printf("Problema de los Monos y los Melocotones:\n");

    // Solución iterativa
    int totalMelocotonesInicialIterativo = calcularMelocotonesIterativo(numeroDeDias);
    printf("Cantidad inicial de melocotones (método iterativo): %d\n", totalMelocotonesInicialIterativo);

    // Solución recursiva
    // Llamamos a la función para calcular los melocotones al inicio del Día 1
    int totalMelocotonesInicialRecursivo = calcularMelocotonesRecursivo(1, numeroDeDias); 
    printf("Cantidad inicial de melocotones (método recursivo): %d\n", totalMelocotonesInicialRecursivo);

    return 0;
}

7. La Caja de Frutas

Se tiene una caja con una cantidad de manzanas que oscila entre 100 y 200. Si las manzanas se agrupan de 4 en 4, sobran 2. Si se agrupan de 7 en 7, sobran 3. Si se agrupan de 9 en 9, sobran 5. El programa determinará la cantidad exacta de manzanas en la caja.

#include <stdio.h>

int main() {
    int cantidadManzanas;

    printf("Buscando la cantidad de manzanas en la caja (entre 100 y 200):\n");

    // Iterar a través de todos los números posibles de manzanas en el rango dado
    for (cantidadManzanas = 100; cantidadManzanas <= 200; cantidadManzanas++) {
        // Comprobar si se cumplen las tres condiciones simultáneamente
        // 1. Al dividir por 4, el resto es 2 (cantidadManzanas % 4 == 2)
        // 2. Al dividir por 7, el resto es 3 (cantidadManzanas % 7 == 3)
        // 3. Al dividir por 9, el resto es 5 (cantidadManzanas % 9 == 5)
        if ((cantidadManzanas % 4 == 2) &&
            (cantidadManzanas % 7 == 3) &&
            (cantidadManzanas % 9 == 5)) {
            
            printf("La cantidad de manzanas en la caja es: %d\n", cantidadManzanas);
            // Si asumimos que solo hay una solución en el rango, podemos salir del bucle
            break; 
        }
    }
    return 0;
}

8. Suma de Series Aritméticas Concatenadas

Este programa calcula la suma de una serie de términos donde cada término está formado por la concatenación de un dígito base a un número n de veces. Por ejemplo, si a=2 y n=3, la suma sería 2 + 22 + 222 = 246.

#include <stdio.h>

int main() {
    int digitoBase;   // El dígito 'a' (ej. 2)
    int numTerminos;  // La cantidad de términos 'n' (ej. 3)
    long long valorTerminoActual = 0; // Almacena el término actual (a, aa, aaa, etc.). Usamos long long para evitar desbordamientos.
    long long sumaAcumulada = 0;     // Almacena la suma total de la serie.

    printf("Ingrese un dígito base (0-9): ");
    scanf("%d", &digitoBase);
    printf("Ingrese la cantidad de términos en la serie: ");
    scanf("%d", &numTerminos);

    // Validaciones básicas de entrada
    if (digitoBase < 0 || digitoBase > 9) {
        printf("Dígito base inválido. Debe ser un número entre 0 y 9.\n");
        return 1;
    }
    if (numTerminos <= 0) {
        printf("La cantidad de términos debe ser un número positivo.\n");
        return 1;
    }

    // Calcular cada término y sumarlo
    for (int i = 1; i <= numTerminos; i++) {
        valorTerminoActual = valorTerminoActual * 10 + digitoBase; // Construye el siguiente término (ej. 2 -> 22 -> 222)
        sumaAcumulada += valorTerminoActual;                       // Añade el término actual a la suma total
    }

    printf("La suma de la serie es: %lld\n", sumaAcumulada);
    return 0;
}

9. Impresión de Patrones

Impresión de la Letra "K" (Patrón de Triángulos)

Este programa genera un patrón de asteriscos que, aunque no es la letra 'K' tipográfica, sigue la lógica de triángulos descendentes y ascendentes que se unen en un punto central. El patrón se forma con un número entero de entrada que define su tamaño.

#include <stdio.h>

int main() {
    int tamanoPatron; // Representa el tamaño base del patrón

    printf("Ingrese un número entero para el tamaño del patrón (2-20): ");
    // El bucle permite la entrada de múltiples valores para probar diferentes patrones
    while (scanf("%d", &tamanoPatron) == 1) { 
        if (tamanoPatron < 2 || tamanoPatron > 20) {
            printf("El tamaño debe estar entre 2 y 20. Intente de nuevo: ");
            continue; // Solicitar una nueva entrada si el tamaño es inválido
        }

        // Parte superior del patrón: triángulo descendente (de tamanoPatron+1 estrellas hasta 2 estrellas)
        for (int fila = 0; fila < tamanoPatron; fila++) {
            for (int col = 0; col <= tamanoPatron - fila; col++) {
                printf("* ");
            }
            printf("\n");
        }

        // Línea central con una sola estrella
        printf("*\n"); 

        // Parte inferior del patrón: triángulo ascendente (de 2 estrellas hasta tamanoPatron+1 estrellas)
        for (int fila = 1; fila <= tamanoPatron; fila++) {
            for (int col = 0; col <= fila; col++) {
                printf("* ");
            }
            printf("\n");
        }
        printf("\nIngrese otro número o Ctrl+D para salir: "); // Indicación para el usuario
    }
    return 0;
}

Impresión de un Rombo/Diamante

Este programa dibuja un patrón de rombo (o diamante) en la consola utilizando asteriscos y espacios. El tamaño del rombo está predefinido en este ejemplo, pero se puede ajustar cambiando la varible alturaMedia.

#include <stdio.h>
#include <math.h> // Necesario para la función abs()

int main() {
    int alturaMedia = 2; // Define la "mitad" de la altura del diamante (para un total de 5 filas: -2, -1, 0, 1, 2)
    int alturaTotal = alturaMedia * 2 + 1; // Calcula la altura total del diamante (ej. 5)

    printf("Patrón de Rombo/Diamante:\n");

    // Bucle para iterar a través de cada fila del diamante
    // 'indiceFila' va desde -alturaMedia hasta +alturaMedia
    for (int indiceFila = -alturaMedia; indiceFila <= alturaMedia; indiceFila++) {
        // Imprimir los espacios iniciales para centrar el rombo
        // La cantidad de espacios es proporcional al valor absoluto del indiceFila
        for (int s = 0; s < abs(indiceFila); s++) {
            printf(" ");
        }

        // Imprimir los asteriscos para la fila actual
        // La cantidad de asteriscos disminuye o aumenta a medida que se aleja del centro
        for (int a = 0; a < alturaTotal - 2 * abs(indiceFila); a++) {
            printf("*");
        }
        printf("\n"); // Ir a la siguiente línea para la próxima fila del patrón
    }
    return 0;
}

10. Números Narcisistas

Un número narcisista (también conocido como número de Armstrong) es un número entero de n dígitos que es igual a la suma de las n-ésimas potencias de sus dígitos. Este programa identifciará todos los números narcisistas de tres dígitos (donde n=3). Por ejemplo, 153 es un número narcisista porque 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153.

#include <stdio.h>

int main() {
    int numeroActual; // El número de tres dígitos que estamos evaluando
    int digitoUnidades, digitoDecenas, digitoCentenas;
    int sumaCubosDigitos;

    printf("Números narcisistas de tres dígitos:\n");

    // Iterar a través de todos los números de tres dígitos, desde 100 hasta 999
    for (numeroActual = 100; numeroActual < 1000; numeroActual++) {
        // Extraer cada dígito del número
        digitoUnidades = numeroActual % 10;          // Obtener el dígito de las unidades
        digitoDecenas = (numeroActual / 10) % 10;    // Obtener el dígito de las decenas
        digitoCentenas = numeroActual / 100;         // Obtener el dígito de las centenas

        // Calcular la suma de los cubos de cada dígito
        sumaCubosDigitos = (digitoUnidades * digitoUnidades * digitoUnidades) +
                           (digitoDecenas * digitoDecenas * digitoDecenas) +
                           (digitoCentenas * digitoCentenas * digitoCentenas);

        // Comprobar si la suma de los cubos de los dígitos es igual al número original
        if (sumaCubosDigitos == numeroActual) {
            printf("%d es un número narcisista.\n", numeroActual);
        }
    }
    return 0;
}

Etiquetas: C programación algoritmos EstructurasDeControl funciones

Publicado el 6-27 19:31