Abro este post para proponer problemas a resolver mediante Java y discutir sobre las posibles soluciones que vayamos proponiendo. Por ejemplo, todos los años, Google, organiza un campeonato a nivel mundial de programación en el cual se les presenta a los participantes una serie de problemas que deben resolver. Este campeonato se divide en distintas fases, en 2012, este problema que presento a continuación correspondía al primero de la ronda clasificatoria:

NÚMEROS RECICLADOS

¿Alguna vez te has sentido frustrado con la televisión porque la gran mayoría de programas son practicamente idénticos, reciclados una y otra vez? Personalmente no veo mucho la televisión, pero me he sentido así alguna vez con los números.

Me explico, una pareja de números enteros distintos (n, m) son reciclados si podemos obtener m moviendo algunos dígitos del final de n al principio sin cambiar su orden. Por ejemplo, (12345, 34512) es una pareja reciclada ya que podemos obtener 34512 moviendo 345 del final de 12345 al principio. Nótese que n y m deben tener el mismo número de cifras y que, ni n ni m pueden tener ceros a la izquierda.

Dados dos números enteros A y B con el mismo número de dígitos y sin ceros a la izquierda, ¿cuántas parejas recicladas distintas (n, m) existen con A <= n < m <= B?

Entrada

La primera línea de la entrada contiene el número de casos a analizar, T. T casos vienen a continuación. Cada caso consiste en una única línea con dos enteros A y B.

Salida

Por cada caso, la salida de nuestro programa contendrá

Case #x: y

, donde x es el número de caso (empezando en 1), e y es el número de parejas recicladas (n, m) diferentes con A <= n < m <= B.

Ejemplo:

Input

4
1 9
10 40
100 500
1111 2222

Output

Case #1: 0
Case #2: 3
Case #3: 156
Case #4: 287

El archivo de entrada para probar vuestro programa es el siguiente:
Input.txt
Y si todo ha funcionado correctamente debe daros un archivo de salida como el siguiente:
Output.txt

Os animo a que propongais soluciones propias a este problema y que propongais otros.
Un saludo.

La solucion que yo he encontrado es la siguiente:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package reciclados;

import java.io.*;
import java.util.Scanner;

/**
 *
 * @author J&B
 */
public class Reciclados 
{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception 
    {
        FileReader fr=new FileReader("C:\\Users\\J&B\\Desktop\\input.txt");
        Scanner teclado=new Scanner(fr);
        PrintWriter pw=new PrintWriter(new FileWriter("C:\\Users\\J&B\\Desktop\\output.txt"));
        int T=teclado.nextInt();
        String [] strNumbers;
        String [] arrNum;
        int casos, mayor, menor;
        boolean space;
        
        strNumbers=new String [T];
        
        for(int i=0; i<T; i++)
        {
            strNumbers [i]=teclado.nextInt()+" "+teclado.nextInt();
        }
        
        for(int i=0; i<T; i++)
        {
            casos=0;
            space=false;
            String temp1="", temp2="";
            
            for(int j=0; j<strNumbers[i].length(); j++)
            {
                if(!space)
                {
                    if(!" ".equals(strNumbers[i].substring(j, j+1)))
                    {
                        temp1+=strNumbers[i].substring(j, j+1);
                    }
                }

                if(space)
                {
                    if(!" ".equals(strNumbers[i].substring(j, j+1)))
                    {
                        temp2+=strNumbers[i].substring(j, j+1);
                    }
                }
                
                if(!space && " ".equals(strNumbers[i].substring(j, j+1)))
                {
                    space=true;
                }
            }
            
            mayor=Math.max(Integer.parseInt(temp1), Integer.parseInt(temp2));
            menor=Math.min(Integer.parseInt(temp1), Integer.parseInt(temp2));
            arrNum=new String[mayor];
            
            for(int j=menor; j<=mayor; j++)
            {
                String temp=String.valueOf(j);
                
                for(int z=1; z<temp.length(); z++)
                {
                    String strRec=temp.substring(z, temp.length())
                            .concat(temp.substring(0, z));
                    if(!"0".equals(strRec.substring(0,1)))
                    {
                        int rec=Integer.parseInt(strRec);

                        if(j<rec && rec<=mayor)
                        {
                            int tamaño=tamaño(arrNum);
                            boolean comprobar=false;
                            for(int d=0; d<tamaño; d++)
                            {
                                if((j+" "+rec).equals(arrNum[d]))
                                {
                                    comprobar=true;
                                    d=tamaño;
                                }
                            }
                            if(!comprobar)
                            {
                                arrNum[tamaño]=j+" "+rec;
                                casos++;
                            }
                        }
                    }
                }
            }
            System.out.println("Caso #"+(i+1)+": procesado.");
            pw.println("Case #"+(i+1)+": "+casos);
        }
        teclado.close();
        fr.close();
        pw.close();
    }
    
    public static int tamaño(String [] arrNum)
    {
        int tamaño1=0;
        for(int z=0; z<arrNum.length; z++)
        {
            if(arrNum[z]==null)
            {
                tamaño1=z;
                z=arrNum.length;
            }
        }
        return tamaño1;
    }
}
25 días más tarde

¿Nadie se anima a intentar resolverlo? Vamos con otro que fue propuesto el año pasado en el Concurso de programación para ciclos formativos Programa-me:

MONEDA

Se desea elaborar un algoritmo para transformar una cantidad de euros al número mínimo de billetes y monedas necesarios para representarla. La cantidad siempre será positiva y sin decimales.

Entrada

El algoritmo recibirá números enteros positivos. El algoritmo terminará la transformación cuando reciba una cantidad de 0 euros.

Salida

Para cada uno de los valores que se reciban, excepto para el 0, la salida será la cantidad a transformar y en cada una de las líneas inferiores se colocará el número mínimo de billetes o monedas de cada clase que se necesitan pa conseguir dicha cantidad. El formato de salida será de la siguiente forma:

99
1 de 50
2 de 20
1 de 5
2 de 2

Entrada de ejemplo

354
1233
941
5995
4739
0

Salida de ejemplo

354
1 de 200
1 de 100
1 de 50
2 de 2
1233
2 de 500
1 de 200
1 de 20
1 de 10
1 de 2
1 de 1
941
1 de 500
2 de 200
2 de 20
1 de 1
5995
11 de 500
2 de 200
1 de 50
2 de 20
1 de 5
4739
9 de 500
1 de 200
1 de 20
1 de 10
1 de 5
2 de 2

Adelante!!!

Esta es una posible solución al problema de la Moneda

import java.io.FileNotFoundException;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.util.Scanner;

public class Moneda {

	public static void main(String[] args) {
		FileReader fr;
		Scanner in;
		FileWriter fichero = null;
        PrintWriter pw = null;
		try {
			fr = new FileReader("/home/input.txt");
			in = new Scanner(fr);
			fichero = new FileWriter("/home/output.txt");
			pw = new PrintWriter(fichero);
			int dinero, centinela;
			do {
				dinero = in.nextInt();
				centinela = dinero;
				if(dinero > 0) pw.println(dinero+ "\n");
				if (dinero>=500) {
					pw.println(dinero/500 + " de 500");
					dinero%=500;
				}
				if(dinero>=200) {
					pw.println(dinero/200 + " de 200");
					dinero%=200;
				}
				if(dinero>=100) {
					pw.println(dinero/100 + " de 100");
					dinero%=100;
				}
				if(dinero>=50) {
					pw.println(dinero/50 + " de 50");
					dinero%=50;
				}
				if(dinero>=20) {
					pw.println(dinero/20 + " de 20");
					dinero%=20;
				}
				if(dinero>=10) {
					pw.println(dinero/10 + " de 10");
					dinero%=10;
				}
				if(dinero>=5) {
					pw.println(dinero/5 + " de 5");
					dinero%=5;
				}
				if(dinero>=2) {
					pw.println(dinero/2 + " de 2");
					dinero%=2;
				}
				if(dinero>0) {
					pw.println(dinero+ " de 1");
				}
				pw.println("\n");
			} while (centinela != 0);		
				in.close();
				fr.close();
		        pw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InputMismatchException e){
			e.printStackTrace();
		}
	}
}

No tiene mucho que ver pero este último problema aplicado a convertir nº a números romanos sale perfecto, empezando por el nº mas grande M = 1000, así sucesivamente hasta I = 1.

Bravo por tu solución tapiasmoreno, únicamente dos apuntes menores.

El primero es que el fichero de salida que genera es erróneo, no por los resultados, sino porque imprimes un salto de línea antes y despúes de cada línea que contiene la cantidad total a desglosar. Esto sucede porque en la linea en que imprimes la cantidad total pones:

pw.println(dinero+ "\n");

Println ya agrega un cambio de línea al final y con "\n" agregar otro.
También imprimes el 0 que finaliza la entrada, que no debe aparecer

Del otro, no estoy seguro al 100%, así que abro debate para quien lo sepa. Donde inicializas el FileReader y el FileWriter:

fr = new FileReader("/home/input.txt");
fichero = new FileWriter("/home/output.txt");

¿Las rutas no deben escribirse con doble barra? Es decir:

fr = new FileReader("//home//input.txt");
fichero = new FileWriter("//home//output.txt");

Un saludo!

Gracias bcurto.
Bueno, lo del 0 al final fue un error, ya lo he solucionado.
Lo del salto de linea lo hice asi porque creo que la salida queda más clara.
Por último, a mi no me da ningun error de compilación ni de ejecución con las rutas escritas con la barra simple, he utilizado eclipse.

arts escribió

No tiene mucho que ver pero este último problema aplicado a convertir nº a números romanos sale perfecto, empezando por el nº mas grande M = 1000, así sucesivamente hasta I = 1.

Pasar a números romanos se complica un poco más que el anterior, por el tema de las repeticiones de los simbolos, la novena unidad, etc. Pero en esencia es muy similar.

Disculpa por la confusión, he felicitado a Arts en lugar de a ti. Ya está corregido.

La verdad no he probado las rutas con barras simples y yo uso Netbeans (no se si esto influye en algo), pero sí recuerdo que en clase nos han dicho que tenemos que usar barras dobles. Aunque si a ti te funciona quizá la diferencia esté en los IDE´s. Si alguien sabe algo más de este tema por favor que nos lo explique.

Por mi parte la solución que he encontrado es la siguiente, la entrada/salida de datos es la estándar, si quisiesemos que tomase los datos de un archivo únicamente deberíamos de modificar esto por un FileReader y un PrintWriter. Yo lo ejecuto desde línea de comandos por lo que ya le doy entrada al archivo desde alli y hago la salida hacia un archivo, por lo que así funciona:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package moneda;

import java.util.Scanner;

/**
 *
 * @author usuario
 */
public class Moneda 
{
	//Creo un array de constantes enteras con los valores de los billetes/monedas de mayor a menor
    static final int [] billetes={500, 200, 100, 50, 20, 10, 5, 2, 1};
    public static void main(String[] args) 
    {
        Scanner sc=new Scanner(System.in);
        int cantidad;
        
        do
        {
			//recojo la cantidad a desglosar
            cantidad=sc.nextInt();
			//Si es distinta de 0 la proceso
            if(cantidad!=0)
            {
                new Moneda().procesar(cantidad);
            }
		//Mientras sea distinta de 0 continua el bucle
        }while(cantidad!=0);
    }
    
    void procesar(int cantidad)
    {
		//Imprimo la cantidad a desglosar
        System.out.println(cantidad);
        
		//Creo un bucle for que recorra el array de los billetes/monedas
        for(int i=0; i<billetes.length; i++)
        {
			//variable que recoge la cantidad de billetes/monedas de cada tipo
            int contador=0;
            
			//Mientras sea mayor que 0 se realizan las siguientes sentencias
            if(cantidad>0)
            {
				//Mientras la cantidad a desglosar sea mayor que la cantidad del array billetes/monedas
                while(billetes[i]<=cantidad)
                {
					//Se cuentan las vueltas
                    contador++;
					//Y restamos a la cantidad el billete seleccionado
                    cantidad-=billetes[i];
                }
                
				//Si el contador es mayor que 0 se imprime esta salida
                if(contador>0)
                {
                    System.out.println(contador+" de "+billetes[i]);
                }
            }
        }
    }
}

Un saludo a todos!!

Vamos con otro problemilla, :

SUDOKU

Descripción del problema

El objetivo del pasatiempos sudoku es rellenar una cuadrícula de 9x9 celdas (81 casillas) dividida en subcudrículas de 3x3 (también llamadas "cajas" o "regiones") con las cifras del 1 al 9 partiendo de algunos números ya dispuestos en algunas de las celdas. La solución de un sudoku siempre es un cuadrado latino, en el que cada fila, cada columna, y cada región no tienen números repetidos (cada número aparece una única vez).
Deseamos diseñar un programa para saber si una solución a un sudoku es correcta o no.

Entrada

El programa leerá el número de casos de prueba al inicio, y para caso de prueba leerá 9 filas de 9 números que corresponderán con el cuadrado latino asociado a una solución del pasatiempo sudoku.

Salida

Para cada solución de un sudoku indicará si la salida es correcta o no imprimiendo SI o NO

Ejemplo de entrada

2
4 2 5 7 1 6 8 3 9
3 6 8 5 4 9 1 7 2
1 9 7 3 8 2 6 5 4
8 4 9 1 6 7 5 2 3
5 3 1 2 9 4 7 6 8
2 7 6 8 5 3 4 9 1
9 1 2 6 7 8 3 4 5
6 8 3 4 2 5 9 1 7
7 5 4 9 3 1 2 8 6
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 1 4 3 6 5 8 9 7
3 6 5 8 9 7 2 1 4
8 9 2 2 1 4 3 6 5
5 3 1 6 4 2 9 7 8
6 4 2 9 7 8 5 3 1
9 7 8 5 3 1 6 4 2

Ejemplo de salida

SI
NO

Un saludo!

bcurto escribió

La verdad no he probado las rutas con barras simples y yo uso Netbeans (no se si esto influye en algo), pero sí recuerdo que en clase nos han dicho que tenemos que usar barras dobles. Aunque si a ti te funciona quizá la diferencia esté en los IDE´s. Si alguien sabe algo más de este tema por favor que nos lo explique.

Hola bcurto, hoy me han aclarado lo de la doble barra, si te fijas en mi código yo puse en el directorio la barra "normal", (/), por eso no me da error.

fr = new FileReader("/home/input.txt");
fichero = new FileWriter("/home/output.txt");

Si hubiera utilizado la barra invertida (), hubiera dado error, si que hay que ponerla doble para que la reconozca como un carácter de escape.

fr = new FileReader("\home\input.txt");
fichero = new FileWriter("\home\output.txt");

Saludos.

Magnifico, duda aclarada. Nunca te acostarás sin saber algo más. jejeje

Bueno como nadie se anima con el sudoku, muestro como lo he solucionado yo.

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;

public class Sudoku {
	static int[][] sudoku = new int[9][9];

	public static void main(String[] args) {
		try {
			FileReader fr = new FileReader("/home/input.txt");
			Scanner in = new Scanner(fr);
			FileWriter fw = new FileWriter("/home/output.txt");
			PrintWriter pw = new PrintWriter(fw,true);
			int casos = in.nextInt();
			while (casos != 0) {
				for (int i = 0; i < 9; i++) {
					for (int j = 0; j < 9; j++) {
						sudoku[i][j] = in.nextInt();
					}
				}
				if (comprobarSudoku()) {
					pw.println("SI");
				} else {
					pw.println("NO");
				}
				casos--;
			}
			in.close();
			fr.close();
			fw.close();
			pw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	} // Fin main

	// Método que comprueba si el sudoku es correcto
	public static boolean comprobarSudoku() {
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				if (!esValido(i, j, sudoku[i][j]))
					return false;
			}
		}
		return true;
	}

	// Método que comprueba si el número ya esta en la linea
	public static boolean comprobarLinea(int fila, int columna, int numero) {
		for (int i = 0; i < 9; i++) {
			if (i == columna) continue;
			if (sudoku[fila][i] == numero) {
				return false;
			}
		}
		return true;
	}

	// Método que comprueba si el número ya esta en la columna
	public static boolean comprobarColumna(int fila, int columna, int numero) {
		for (int i = 0; i < 9; i++) {
			if (i == fila) continue;
			if (sudoku[i][columna] == numero) {
				return false;
			}
		}
		return true;
	}

	// Método que comprueba si el numero ya esta en la region
	public static boolean comprobarRegion(int fila, int columna, int numero) {
		// Coodenadas de la region
		int rF = region(fila);
		int rC = region(columna);
		for (int i = rF; i <= (rF + 2); i++) {
			for (int j = rC; j <= (rC + 2); j++) {
				if ((i == fila) && (j == columna)) continue;
				if (sudoku[i][j] == numero) {
					return false;
				}
			}
		}
		return true;
	}

	// Método que recibe como parametro la fila o la columna y devuelve
	// la región a la que pertenece
	public static int region(int x) {
		int reg = 0;
		switch (x / 3) {
		case 0:
			reg = 0;
			break;
		case 1:
			reg = 3;
			break;
		case 2:
			reg = 6;
			break;
		}
		return reg;
	}

	// Método que realiza las tres comprobaciones
	public static boolean esValido(int fila, int columna, int numero) {
		return (comprobarLinea(fila,columna, numero) && comprobarColumna(fila, columna, numero)
				&& comprobarRegion(fila, columna, numero));
	}
} // Fin de la clase

Se te dan bien los problemas analiticos eh!!!
De momento somos los únicos que nos animamos a proponer soluciones, vamos a continuar con el tema y confiar en que la gente se vaya animando.

Quiero compartir con vosotros (si hay alguien mas que tapiasmoreno y yo, xD) que la inscripción para el Google Code Jam está abierta. Es un concurso a nivel mundial de programación organizado por Google. Probablemente casi todos los que andamos por este foro seamos estudiantes y nos estemos iniciando en esto de la programación, por lo menos es mi caso. Por ello tenemos harto dificil hacer algo importante en este concurso, ya que en el compiten los mejores programadores a nivel mundial. Yo me he inscrito más que nada por poner a prueba mis progresos, ver que nivel tengo y, sobre todo, por aprender de los mejores (es posible ver las soluciones propuestas por otros participantes una vez haya terminado el concurso).
Animo a todos a que participen, ya que, además de tener el aliciente de un premio de 15000$ para el primero, los 25 mejores irán a las oficinas centrales de Google a la ronda final y, probablemente, saldrán de allí con decenas de empresas rifándoselos independientemente de como hayan quedado. Como sé que existe una probabilidad muuuuuuuuuuy remota de que esto suceda (por lo menos para mi), también os digo que se aprende más viendo lo que hacen los mejores que en clase, y quien sabe, quizá llegue el día que alguno de nosotros sea uno de ellos....

Bueno no me lío más, aquí la solución que yo propongo al problema del sudoku y animo a tapiasmoreno a que nos presente algún problemilla.

package sudoku;

import java.util.HashSet;
import java.util.Scanner;

/**
 *
 * @author J&B
 */
public class Sudoku 
{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) 
    {
        Scanner sc=new Scanner(System.in);
        //Recojo los casos
        int casos=sc.nextInt();
        
        //Bucle que recoje cada caso
        for(int i=0; i<casos; i++)
        {
            //Proceso cada caso
            new Sudoku().procesar(sc);
        }
    }
    
    void procesar(Scanner sc)
    {
        int [][] sudoku=new int[9][9];
        boolean correcto=true;
        
        //Recojo los numeros del sudoku
        for(int i=0; i<9; i++)
        {
            for(int j=0; j<9; j++)
            {
                sudoku[i][j]=sc.nextInt();
            }
        }
        
        //compruebo las filas y columnas
        for(int i=0; i<9; i++)
        {
            for(int j=0; j<9; j++)
            {
                int fila=sudoku[i][j], columna=sudoku[j][i];
                
                for(int k=j+1; k<9; k++)
                {
                    if(sudoku[i][j]==sudoku[i][k])
                    {
                        //Si algun numero se repite en una fila
                        correcto=false;
                        k=9;j=9;i=9;
                    }
                    if(sudoku[j][i]==sudoku[k][i])
                    {
                        //Si algun número se repite en una columna
                        correcto=false;
                        k=9;j=9;i=9;
                    }
                }
                
                //Recojo las regiones (si las filas y columnas son correctas)
                if(correcto && i%3==2 && j%3==2)
                {
                    int [][] region=
                    {
                        {sudoku[i-2][j-2], sudoku[i-2][j-1], sudoku[i-2][j]},
                        {sudoku[i-1][j-2], sudoku[i-1][j-1], sudoku[i-1][j]},
                        {sudoku[i][j-2], sudoku[i][j-1], sudoku[i][j]}
                    };

                    //Las envio a comprobar
                    correcto=comprobar(region);
                }
            }
        }
        
        if(correcto)
        {
            System.out.println("SI");
        }
        else
        {
            System.out.println("NO");
        }
    }
    
    boolean comprobar(int [][] region)
    {
        boolean correcto=true;
        HashSet <Integer> hs=new HashSet<> ();
        
        for(int i=0; i<3; i++)
        {
            for(int j=0; j<3; j++)
            {
                /* Añado cada elemento a un hashset que devuelve false
                 * si se intenta añadir un elemento repetido*/
                if(!hs.add(region[i][j]))
                {
                    correcto=false;
                }
            }
        }
        return correcto;
    }
}
11 días más tarde

Bueno, pues vamos con un nuevo problema. Esta vez extraido de la ronda 1A del Google Code Jam de 2010.

ROTATE

Descripción

En el apasionante juego de Conecta-K (K=4 es el más conocido), piezas rojas y azules son insertadas en un tablero de NxN huecos. El tablero está en posición vertical, por lo que al insertar una pieza esta cae hasta la casilla de su columna situada más abajo que se encuentre libre. Por ejemplo, consideremos las dos siguientes configuraciones:

  • Posiciones permitidas -

      .......
      .......
      .......
      ....R..
      ...RB..
      ..BRB..
      .RBBR..[/quote]
  • Posiciones no permitidas -

      .......
      .......
      .......
      .......
      ..BR... <-Mal
      ...R...
      .RBBR..[/quote]

En estas configuraciones, cada '.' representa una casilla vacia, cada 'R' representa una ficha roja y cada 'B' representa una ficha azul. La primera configuración está permitida, pero la segunda no. Esto es porque en la tercera columna (señalada con un Mal) hay una ficha que no ha bajado hasta la casilla más baja libre.

Un jugador gana si es capaz de situar al menos K fichas de su color de forma consecutiva, tanto si es horizontal, vertical o diagonalmente.

En el "Posiciones permitidas", ambos jugadores han conseguido situar 2 fichas propias de forma consecutiva, pero ninguno de los dos ha conseguido conectar 3.

En estos momentos te encuentras disputando una partida de Conecta-K y dispones de un plan para ganar. Cuando tu oponente no mire, vas a girar el tablero 90 grados en el sentido de las agujas del reloj. La gravedad provocará que las piezas caigan de nuevo hasta la parte inferior del tablero situándose en nuevas posiciones. Lo entenderemos mejor con un ejemplo gráfico:

  • Comienzo -

    .......
    .......
    .......
    ...R...
    ...RB..
    ..BRB..
    .RBBR..

  • Giro -

    .......
    R......
    BB.....
    BRRR...
    RBB....
    .......
    .......

  • Gravedad -

    .......
    .......
    .......
    R......
    BB.....
    BRR....
    RBBR...

Desafortunadamente, solo tendrás una oportunidad de girar el tablero sin que tu oponente se entere. Así que debes elegir el momento adecuado para hacer el giro.

Dada una cierta configuración de tablero debes determinar que jugador o jugadores ganarán si realizas el giro.

Notas:
Solo puedes rotar el tablero una vez
Asumiremos que la gravedad solo afectará cuando el tablero esté completamente rotado.
Solo comprobaremos quien o quienes han ganado una vez la gravedad haya hecho efecto.

Entrada

La primera línea de la entrada contiene el número de casos, T. T casos vienen a continuación. Cada caso comienza con una línea que contiene dos enteros N y K. Las siguientes N líneas contendrán exactamente N caracteres cada una, mostrando la configuración inicial del tablero y usando el mismo formato descrito anteriormente.

La posición inicial de cada test siempre será una posición permitida, no es necesario comprobar esto. Y, en ella, ningún jugador tendrá conectadas K fichas.

Salida

Para cada caso daremos salida a una línea con el siguiente patrón: "Case #x: y" (sin las comillas). Donde x es el número de caso empezando en 1, e y es uno de los siguientes "Red", "Blue", "Both" y "Neither". Aquí, la y, indicará que jugador o jugadores han ganado después de rotar el tablero.

Ejemplo

Entrada

4
7 3
.......
.......
.......
...R...
...BB..
..BRB..
.RRBR..
6 4
......
......
.R...R
.R..BB
.R.RBR
RB.BBB
4 4
R...
BR..
BR..
BR..
3 3
B..
RB.
RB.

Salida

Case #1: Neither
Case #2: Both
Case #3: Red
Case #4: Blue

Aquí teneis el fichero de entrada para probar vuestras soluciones y el de salida para comparar:
Fichero de entrada
Fichero de salida

Un saludo.

20 días más tarde

Visto el poco exito que está generando este post lo doy por cerrado. Ahí va mi solución a este último ejercicio:

package rotate;

import java.io.FileReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;


public class Rotate 
{

    
    public static void main(String[] args) throws Exception
    {
        Scanner sc=new Scanner(new FileReader("input.txt"));
        PrintWriter pw=new PrintWriter("output.txt");
        int casos=sc.nextInt();
        
        for(int i=1; i<=casos; i++)
        {
            System.out.print("Procesando caso "+i+"...");
            int N=sc.nextInt(), K=sc.nextInt();
            sc.nextLine();
            pw.print("Case #"+i+": ");
            new Rotate().procesar(N, K, sc, pw);
            System.out.println("procesado");
        }
        pw.flush();
        pw.close();
        sc.close();
    }
    
    void procesar(int N, int K, Scanner sc, PrintWriter pw)
    {
        String [] tablero=new String[N];
        String [] rotado=new String[N];
        Arrays.fill(rotado, "");
        boolean compRojo = false, compAzul = false;
        
        for(int i=0; i<N; i++)
        {
            tablero[i]=sc.nextLine();
        }
        
        for(int i=N-1; i>=0; i--)
        {
            String temp="";
            for(int j=N-1; j>=0; j--)
            {
                while(j>=0 && tablero[i].charAt(j)!=&#39;.&#39;)
                {
                    temp+=tablero[i].charAt(j);
                    j--;
                }
            }
            for(int j=N-1; j>=0; j--)
            {
                if(j>=temp.length())
                {
                    rotado[N-1-j]+=".";
                }
                else
                {
                    rotado[N-1-j]+=temp.charAt(j);
                }
            }
        }
        
        for(int i=0; i<N; i++)
        {
            for(int j=0; j<N; j++)
            {
                if(rotado[i].charAt(j)!=&#39;.&#39;)
                {
                    String temp="";
                    if(rotado[i].charAt(j)==&#39;R&#39;)
                    {
                        if(!compRojo && i-K>=-1)//arriba
                        {
                            for(int m=i; m>i-K; m--)
                            {
                                temp+=rotado[m].charAt(j);
                            }
                            compRojo=comprobar(temp, "R");
                            temp="";
                            if(!compRojo && j-K>=-1)//arriba izda
                            {
                                for(int m=i, n=j; m>i-K && n>j-K; m--, n--)
                                {
                                    temp+=rotado[m].charAt(n);
                                }
                                compRojo=comprobar(temp, "R");
                                temp="";
                            }
                            if(!compRojo && j+K<N)//arriba dcha
                            {
                                for(int m=i, n=j; m>i-K && n<j+K; m--, n++)
                                {
                                    temp+=rotado[m].charAt(n);
                                }
                                compRojo=comprobar(temp, "R");
                                temp="";
                            }
                        }
                        if(!compRojo && j-K>=-1)//izda
                        {
                            for(int m=j; m>j-K; m--)
                            {
                                temp+=rotado[i].charAt(m);
                            }
                            compRojo=comprobar(temp, "R");
                            temp="";
                        }
                        if(!compRojo && i+K<N)//abajo
                        {
                            for(int m=i; m<i+K; m++)
                            {
                                temp+=rotado[m].charAt(j);
                            }
                            compRojo=comprobar(temp, "R");
                            temp="";
                            if(!compRojo && j-K>=-1)//abajo izda
                            {
                                for(int m=i, n=j; m<i+K && n>j-K; m++, n--)
                                {
                                    temp+=rotado[m].charAt(n);
                                }
                                compRojo=comprobar(temp, "R");
                                temp="";
                            }
                            if(!compRojo && j+K<N)//abajo dcha
                            {
                                for(int m=i, n=j; m<i+K && n<j+K; m++, n++)
                                {
                                    temp+=rotado[m].charAt(n);
                                }
                                compRojo=comprobar(temp, "R");
                                temp="";
                            }
                        }
                        if(!compRojo && j+K<N)//dcha
                        {
                            for(int m=j; m<j+K; m++)
                            {
                                temp+=rotado[i].charAt(m);
                            }
                            compRojo=comprobar(temp, "R");
                            temp="";
                        }
                    }
                    else
                    {
                        if(!compAzul && i-K>=-1)//arriba
                        {
                            for(int m=i; m>i-K; m--)
                            {
                                temp+=rotado[m].charAt(j);
                            }
                            compAzul=comprobar(temp, "B");
                            temp="";
                            if(!compAzul && j-K>=-1)//arriba izda
                            {
                                for(int m=i, n=j; m>i-K && n>j-K; m--, n--)
                                {
                                    temp+=rotado[m].charAt(n);
                                }
                                compAzul=comprobar(temp, "B");
                                temp="";
                            }
                            if(!compAzul && j+K<N)//arriba dcha
                            {
                                for(int m=i, n=j; m>i-K && n<j+K; m--, n++)
                                {
                                    temp+=rotado[m].charAt(n);
                                }
                                compAzul=comprobar(temp, "B");
                                temp="";
                            }
                        }
                        if(!compAzul && j-K>=-1)//izda
                        {
                            for(int m=j; m>j-K; m--)
                            {
                                temp+=rotado[i].charAt(m);
                            }
                            compAzul=comprobar(temp, "B");
                            temp="";
                        }
                        if(!compAzul && i+K<N)//abajo
                        {
                            for(int m=i; m<i+K; m++)
                            {
                                temp+=rotado[m].charAt(j);
                            }
                            compAzul=comprobar(temp, "B");
                            temp="";
                            if(!compAzul && j-K>=-1)//abajo izda
                            {
                                for(int m=i, n=j; m<i+K && n>j-K; m++, n--)
                                {
                                    temp+=rotado[m].charAt(n);
                                }
                                compAzul=comprobar(temp, "B");
                                temp="";
                            }
                            if(!compAzul && j+K<N)//abajo dcha
                            {
                                for(int m=i, n=j; m<i+K && n<j+K; m++, n++)
                                {
                                    temp+=rotado[m].charAt(n);
                                }
                                compAzul=comprobar(temp, "B");
                                temp="";
                            }
                        }
                        if(!compAzul && j+K<N)//dcha
                        {
                            for(int m=j; m<j+K; m++)
                            {
                                temp+=rotado[i].charAt(m);
                            }
                            compAzul=comprobar(temp, "B");
                            temp="";
                        }
                    }
                }
            }
        }
        
        if(compRojo || compAzul)
        {
            if(compRojo && compAzul)
            {
                pw.println("Both");
            }
            else
            {
                if(compAzul)
                {
                    pw.println("Blue");
                }
                else
                {
                    pw.println("Red");
                }
                
            }
            
        }
        else
        {
            pw.println("Neither");
        }
        
    }
    
    boolean comprobar(String cadena, String letra)
    {
        boolean correcto=true;
        
        for(int i=0; i<cadena.length(); i++)
        {
            if(!letra.equals(String.valueOf(cadena.charAt(i))))
            {
                correcto=false;
                i=cadena.length();
            }
        }
        
        return correcto;
    }
}

Un saludo a todos.