Cómo determinar el número total de triángulos degenerados sin bucles de una longitud determinada (más de 3)

Degenerar puede significar cosas diferentes en diferentes circunstancias, pero supondré que te refieres a triángulos con un ángulo de [matemáticas] 180 [/ matemáticas]. En tales triángulos, la suma de las longitudes de dos lados es igual a la longitud del tercer lado.

Asumiré además que está haciendo esto en una computadora, ya que .5 segundos son terriblemente cortos para una persona.

Deje que [math] n [/ math] sea la cantidad de longitudes que tiene.

  1. El enfoque totalmente ingenuo: para cada conjunto de tres longitudes, verifique si dos suman al tercero.
    1. Esto se ejecuta en [math] O ({{n} \ choose {3}}) [/ math] time, también conocido como [math] O (n ^ 3) [/ math]
  2. Un poco menos ingenuo: haga una nueva lista de todas las sumas de pares y cuente las intersecciones con la lista original.
    1. todavía [matemáticas] O (n ^ 3) [/ matemáticas]
  3. Cómo llegar a algún lado: ordena la lista de longitudes. Luego genera una nueva lista de sumas de pares que también se ordena. Finalmente, encuentre la intersección mediante búsqueda binaria para cada uno de los elementos de la primera lista en la segunda.
    1. Bien hecho, esto es [matemáticas] O (n ^ 2) [/ matemáticas] porque hacer la segunda lista es el cuello de botella.
    2. Hacer la segunda lista ya ordenada es un poco complicado. Vea 4b para obtener una pista sobre cómo hacerlo. Sin embargo, en la práctica, solo generarlo normalmente y usar el algoritmo de clasificación correcto será casi tan rápido.
  4. Ajustándolo para una aplicación práctica:
    1. Ordenar la lista: [matemáticas] O (n \ log (n)) [/ matemáticas]
    2. Genere la segunda lista dinámicamente mientras verifica las intersecciones con la primera. Esto sigue siendo [matemática] O (n ^ 2) [/ matemática], pero no necesita almacenar todo en la memoria y la parte de búsqueda se vuelve mucho más rápida. En lugar de la búsqueda binaria para cada elemento, utiliza un método similar al de combinar dos matrices ordenadas que leen cada una una vez.

EDITAR: ya no se nos permite usar bucles.

Así que aquí hay una implementación ingenua de Python.

herramientas de importación
pares = itertools.product (longitudes, longitudes)
pares = lista (mapa (lambda x: suma (x), pares))
cuenta = suma (lista (mapa (lambda x: x en longitudes, pares))) / 2

Dividimos por dos porque en realidad contamos cada triángulo dos veces: como (a, b, c) y como (b, a, c).

El rendimiento de esto ciertamente puede mejorarse, pero en realidad no es tan lento a menos que su lista sea enorme.

Encontrar un algoritmo O (n ^ 3) es bastante fácil y se puede hacer en pocas líneas, pero encontrar un algoritmo O (n ^ 2) es un poco más difícil. Aquí hay una posible solución que escribí rápidamente en F # que debería ejecutarse en tiempo O (n ^ 2):

Comparación de tipos = Menor | Igual | Mayor

// Función genérica útil para muchos problemas.
// Asume que slistA y slistB están ordenados y que comp es monótono.
// Utiliza esto para encontrar todos los pares “Iguales” en el tiempo O (longitud (slistA) + longitud (slistB)).
let rec scanCompare comp slistA slistB =
partido (slistA, slistB) con
| (x :: xs, y :: ys) -> // Divide slistA en el primer elemento xy el resto xs. Lo mismo para slistB. Cae al siguiente caso si alguno está vacío.
emparejar comp xy con
| Menor -> scanCompare comp xs slistB // Avanzar en ListA si su primer elemento es demasiado pequeño
| Mayor -> scanComparar comp slistA ys // Avanzar en ListB si su primer elemento es demasiado pequeño
| Equal -> (x, y): 🙁 scanCompare comp xs slistB) // Recopila el par de primeros elementos si comp devuelve “Equal”.
| _ -> [] // Devuelve cuando cualquiera de las listas de entrada está agotada.

let triangleCheck abc =
partido (a + b) – c con
El | x cuando x <0 -> Menor
El | x cuando x> 0 -> Mayor
| _ -> Igual

dejar degenTriangles sideslist =
let sortedlist = List.sort sidelist
[para x en sortedlist -> scanCompare (triangleCheck x) sortedlist sortedlist] |>
List.concat |>
List.map (diversión (x, y) -> (yx, x, y))

degenTriangles devuelve una lista de todos los triángulos posibles que se pueden construir combinando los elementos de sidesList, como tuplas con el lado más grande al final (contando las permutaciones de lados más pequeños dos veces). Ejemplo:

> degenTriangles [1; 2; 3; 8; 10; 14; 18; 19] ;;
val it: (int * int * int) list =
[(1, 1, 2); (1, 2, 3); (1, 18, 19); (2, 1, 3); (2, 8, 10); (8, 2, 10);
(8, 10, 18); (10, 8, 18); (18, 1, 19)]

Satisface el criterio de “no bucles” mediante el uso de la recursividad y la comprensión de listas.

Alternativamente, pero rompiendo el criterio de “no bucles”, aquí hay una versión optimizada de C ++ del mismo algoritmo escrito en un estilo más imperativo:

// Parte genérica del código que mantendría como funciones de biblioteca

enum class CompResult {menor, igual, mayor};

plantilla
T compareAccumulate (T init, InputIt firstA, const InputIt lastA, InputIt firstB, const InputIt lastB, TrinaryComparison comp, TrinaryOperation op)
{
while (firstA! = lastA && firstB! = lastB) {
switch (comp (* firstA, * firstB)) {
case CompResult :: less:
++ firstA;
descanso;
caso CompResult :: mayor:
++ firstB;
descanso;
caso CompResult :: igual:
init = op (* firstA, * firstB, init);
++ firstA;
}
}
return init;
}

plantilla
CompResult en línea trinComp (const T a, const T b)
{
si (a return CompResult :: less;
más si (a> b)
return CompResult :: mayor;
más
return CompResult :: igual;
}

// Parte específica del problema:

plantilla
int triangleCount (entrada std :: vector )
{
std :: sort (input.begin (), input.end ());
int suma = 0;
const auto end = input.end ();
T k;
for (auto i = input.begin (); i! = end; ++ i) {
k = * i;
sum + = compareAccumulate (0, i, end, i, end,
[k] (T x, T y) {return trinComp
(x + k, y); },
[] (T a, T b, int x) {return x + 1; });
}
suma de retorno;
}

que es el doble que la versión F #, pero podría ser más fácil de leer si está acostumbrado a programas escritos en un estilo imperativo. Solo cuenta el número de triángulos en lugar de enumerarlos, y se ajusta para no contarlos dos veces. Debe manejar entradas de unos pocos miles de elementos en menos de un segundo.

More Interesting

¿Cómo funciona la calculadora HSBC?

¿Qué ventajas tienen las matemáticas mayores que recién comienzan a estudiar la programación en comparación con la especialización CS?

¿Es posible convertir una imagen a una fórmula matemática?

¿Cuáles son algunos temas imprescindibles en matemáticas discretas y probabilidad de programación competitiva?

¿Cuál es la intuición detrás de los algoritmos aleatorios y la aleatorización en general?

¿Qué es el retorno 0 en C?

¿Cuál es el papel de las matemáticas en la programación?

¿Qué nivel de matemáticas necesito tener si quiero convertirme en un buen programador gráfico?

¿Cuáles son los fundamentos matemáticos de la inteligencia artificial?

¿Cuáles son los pasos que debo seguir para dominar las matemáticas? ¿Y cuál es la forma más rápida de alcanzar este objetivo?

Dada una matriz que contiene elementos [matemática] N [/ matemática] y consultas [matemática] Q [/ matemática], cada consulta contiene 3 enteros [matemática] L [/ matemática], [matemática] R [/ matemática] y [matemática ] K [/ matemáticas]. Para cada uno, informe la suma de cada elemento [math] K ^ {th} [/ math] entre [math] L [/ math] y [math] R [/ math] (a partir de [math] L [/ math] )

¿Es la formación lineal la mejor producción de clasificación?

¿De qué sirve encontrar el complemento de uno y dos?

¿Qué es una explicación intuitiva de P = NP?

¿Cuál es el significado de la teoría de la complejidad del caso promedio?