Acerca de la pregunta ... Nunca pidió la solución óptima y este tipo de preguntas no quiere eso. Necesita escribir un algoritmo de propósito general para manejar este problema y una búsqueda de fuerza bruta para encontrar la mejor solución no es factible para las cadenas que pueden tener megabytes de longitud. También noté tarde que se garantiza que habrá el mismo número de 0 y 1, pero creo que es más interesante trabajar con el caso general en el que puede haber diferentes números de 0 y 1. En realidad, no se garantiza que sea una solución en todos los casos si la longitud de la cadena de entrada es menor que 7, incluso en el caso en que tenga 2 0s y 2 1s.
Tamaño 3: Sólo un dígito por lo que está ordenada por definición (UU0 UU1 0UU 1UU)
Tamaño 4: No hay manera de alterar el orden. No hay movimientos si UU está en el medio, y solo se intercambia con ambos dígitos si está al final (1UU0 sin movimientos, UU10-> 10UU-> UU10, etc.)
Tamaño 5: UU en el centro puede solo mueva al extremo y no cambie el orden de los 0s y 1s (1UU10-> 110UU).UU en un extremo puede moverse a la mitad y no cambiar el orden, pero solo volver al mismo extremo para que no le sirva (UU110-> 11UU0-> UU110). La única forma de cambiar los dígitos es si el UU está en un extremo y se intercambia con el extremo opuesto. (UUABC-> BCAUU o ABCUU-> UUCAB). Esto significa que si UU está en las posiciones 0 o 2 puede resolver si 0 está en el medio (UU101-> 011UU o UU100-> 001UU) y si UU está en las posiciones 1 o 3 puede resolver si 1 está en el medio (010UU-> UU001 o 110UU-> UU011). Cualquier otra cosa ya está resuelta o no puede resolverse. Si necesitamos manejar este caso, diría que es un código duro. Si está ordenado, devuelve el resultado (sin movimientos). Si UU está en el medio en alguna parte, muévelo hasta el final. Cambie desde el final al otro extremo y ese es el único intercambio posible, ya sea que esté ordenado o no.
Tamaño 6: Ahora tenemos una posición en la que podemos tener una cadena especificada de acuerdo con las reglas donde podemos realizar movimientos pero donde no puede haber solución. Este es el punto problemático con cualquier algoritmo, porque creo que una condición de cualquier solución debería ser que te avisará si no se puede resolver. Por ejemplo, 0010, 0100, 1000, 1011, 1100, 1101 y 1110 se pueden resolver sin importar dónde se ubique el UU y los peores casos tardan 4 movimientos en resolverse. 0101 y 1010 solo pueden resolverse si UU está en una posición impar. 0110 y 1001 solo pueden resolverse si UU se encuentra en una posición pareja (final o central).
Creo que la mejor manera será algo como lo siguiente, pero aún no lo he escrito. Primero, asegúrese de colocar un '1' al final de la lista. Si el final es actualmente 0, mueva UU hasta el final y luego muévala a la última posición '1': 1. Después de eso, mueva continuamente UU al primer '1', luego al primer '0' después de la nueva UU. Esto moverá todos los 0 al comienzo de la lista. He visto una respuesta similar en el otro sentido, pero no tuvo en cuenta el personaje final en ninguno de los extremos. Esto puede dar lugar a problemas con valores pequeños aún (es decir, 001UU01, no se puede mover al primer 1, mover al final 00101UU nos permite movernos al inicio pero deja 0 al final 00UU110).
Supongo que se pueden codificar casos especiales como ese. Sin embargo, creo que puede haber un algoritmo mejor. Por ejemplo, podría usar los dos primeros caracteres como una 'variable de intercambio temporal. Pondría UU allí y luego haría combinaciones de operaciones en otros para dejar atrás a UY al comienzo. Por ejemplo, UUABCDE puede intercambiar AB con CD o DE o BC CON DE (BCAUUDE-> BCADEUU-> UUADEBC).
Otra cosa posible sería tratar los caracteres como dos bloques de dos bits base-3 0101UU0101 se mostrará como 11C11 o 3593. Tal vez también algo así como una combinación de intercambios codificados. Por ejemplo, si alguna vez ves 11UU, mueve UU a la izquierda 2. Si alguna vez ves UU00, mueve UU a la derecha dos. Si ve UU100, o UU101, mueva UU a la derecha 2 para obtener 001UU o 011UU.
Tal vez otra posibilidad sería algún algoritmo para mover 0s izquierda del centro y derecha 1s del centro (si se da que hay el mismo número de 0s y 1s.
Tal vez sería mejor trabajar en una estructura que solo contenía 0 y 1 con una posición para UU.
Quizás observe mejor la condición resultante, permitiendo que UU esté en cualquier lugar de la cadena, estas condiciones DEBEN cumplirse: No hay 0 después de Length/2 No 1s antes (Longitud/2-1)
Quizás th Hay reglas más generales, como que es realmente bueno intercambiar UU con 10 en este caso '10111UU0' porque un '0' está después de UU ahora y eso le permitiría mover el nuevo 00 al lugar donde estaba el 10 (10111UU0-> UU111100 -> 001111UU).
De todos modos, aquí está el código de fuerza bruta en C#. La entrada es una cadena y un diccionario vacío.Se llena el diccionario con todas las posibles cadena resultante como las claves y la lista de pasos más cortos para llegar allí como el valor:
Llamar:
m_Steps = new Dictionary<string, List<string>>();
DoSort("UU1010011101", new List<string>);
Incluye DoTests() que llama DoSort para cada cadena sea posible con la cantidad dada de dígitos (sin incluir UU):
Dictionary<string, List<string>> m_Steps = new Dictionary<string, List<string>>();
public void DoStep(string state, List<string> moves) {
if (m_Steps.ContainsKey(state) && m_Steps[state].Count <= moves.Count + 1) // have better already
return;
// we have a better (or new) solution to get to this state, so set it to the moves we used to get here
List<string> newMoves = new List<string>(moves);
newMoves.Add(state);
m_Steps[state] = newMoves;
// if the state is a valid solution, stop here
if (state.IndexOf('1') > state.LastIndexOf('0'))
return;
// try all moves
int upos = state.IndexOf('U');
for (int i = 0; i < state.Length - 1; i++) {
// need to be at least 2 before or 2 after the UU position (00UU11 upos is 2, so can only move to 0 or 4)
if (i > upos - 2 && i < upos + 2)
continue;
char[] chars = state.ToCharArray();
chars[upos] = chars[i];
chars[upos + 1] = chars[i + 1];
chars[i] = chars[i + 1] = 'U';
DoStep(new String(chars), newMoves);
}
}
public void DoTests(int digits) { // try all combinations
char[] chars = new char[digits + 2];
for (int value = 0; value < (2 << digits); value++) {
for (int uupos = 0; uupos < chars.Length - 1; uupos++) {
for (int i = 0; i < chars.Length; i++) {
if (i < uupos)
chars[i] = ((value >> i) & 0x01) > 0 ? '1' : '0';
else if (i > uupos + 1)
chars[i] = ((value >> (i - 2)) & 0x01) > 0 ? '1' : '0';
else
chars[i] = 'U';
}
m_Steps = new Dictionary<string, List<string>>();
DoSort(new string(chars), new List<string>);
foreach (string key in m_Steps.AllKeys))
if (key.IndexOf('1') > key.LastIndexOf('0')) { // winner
foreach (string step in m_Steps[key])
Console.Write("{0}\t", step);
Console.WriteLine();
}
}
}
}
Buen problema. ¿Ha sido cargado a un juez en línea después del concurso? Si es así, ¿podrías vincularlo? – IVlad
No, no se publicó nada. – KovBal
Me gustaría señalar que la parte más interesante de esta tarea es que el recuento de U siempre es 2, mientras que los ceros y unos pueden ser por ejemplo 3. Esto lo hace mucho más difícil: '0101UU01' =>' 0UU11001' => '001110UU' =>' 00UU1011' => '00011UU1' (tal vez hay una forma más rápida, pero acabo de dar un ejemplo de lo difícil que puede ser). – bezmax