El principio y uso del algoritmo STL next_permutation

Fuente: http: //leonard1853.iteye.com/blog/1450085

1. Encontrado next_permutation (permutación: el significado de secuencia)

Hoy encontré una pregunta simple en TC (SRM531-Division Two-Level One), que es encontrar la secuencia de diccionario más pequeña de una matriz dada que no está organizada en orden ascendente (la secuencia de números A es lexicográficamente más pequeña que B si A contiene un número menor en la primera posición en la que difieren).

La solución es muy simple, es decir, ordenar la matriz (orden ascendente) y luego encontrar la primera posición intercambiable de principio a fin (porque puede haber números duplicados).

Finalmente, observe las soluciones de otras personas. Después de ordenar, use una función next_permutaion en STL para encontrar directamente la primera secuencia que no está en orden ascendente.

2. Principio de implementación de next_permutation

Encontré esta función en "Análisis de código fuente STL", aquí hay una breve descripción del principio:

En STL, además de next_permutation, también hay una función prev_permutation, las cuales se utilizan para calcular permutaciones y combinaciones. El primero es encontrar la siguiente permutación y combinación, y el segundo es encontrar la permutación y combinación anteriores. El llamado "siguiente" y "anterior", el libro da un ejemplo simple: para la secuencia {a, b, c}, cada elemento es más pequeño que el último, según la secuencia del diccionario, después de fijar a, a es mayores que bc Son todos pequeños, c es mayor que b, su siguiente secuencia es {a, c, b}, y la secuencia anterior de {a, c, b} es {a, b, c}, lo mismo puede deducir las seis secuencias son: {a, b, c}, {a, c, b}, {b, a, c}, {b, c, a}, {c, a, b}, {c, b , a}, donde {a, b, c} no tiene un elemento anterior y {c, b, a} no tiene un elemento siguiente.

El prototipo de función de next_permutation es el siguiente:

template<class BidirectionalIterator>  
bool next_permutation(  
      BidirectionalIterator _First,   
      BidirectionalIterator _Last  
);  
template<class BidirectionalIterator, class BinaryPredicate>  
bool next_permutation(  
      BidirectionalIterator _First,   
      BidirectionalIterator _Last,  
      BinaryPredicate _Comp  
 );  

Para el tercer parámetro de la segunda función sobrecargada, el orden de comparación predeterminado es menor que. Si se encuentra la siguiente secuencia, devuelve verdadero; de lo contrario, devuelve falso.

El principio de implementación de la función es el siguiente:

En la secuencia actual, busque dos elementos adyacentes desde la cola hacia el frente, el primero está marcado como i, el último está marcado como ii, y i < ii. Luego busque otro elemento j desde el final . Si i <* j se satisface , el elemento i-ésimo y el elemento j-ésimo se intercambian, y todos los elementos después del elemento i-ésimo (incluido ii) se ordenan al revés, que es, para encontrar La siguiente secuencia es arriba.

El código se implementa de la siguiente manera:

template<class BidirectionalIterator>  
bool next_permutation(  
      BidirectionalIterator first,   
      BidirectionalIterator last  
)  
{
    
      
    if(first == last)  
        return false; //空序列  
  
    BidirectionalIterator i = first;  
    ++i;  
    if(i == last)  
        return false;  //一个元素,没有下一个序列了  
      
    i = last;  
    --i;  
  
    for(;;) {
    
      
        BidirectionalIterator ii = i;  
        --i;  
        if(*i < *ii) {
    
      
            BidirectionalIterator j = lase;  
            while(!(*i < *--j));  
  
            iter_swap(i, j);  
            reverse(ii, last);  
            return true;  
        }  
          
        if(i == first) {
    
      
            reverse(first, last);  //全逆向,即为最小字典序列,如cba变为abc  
            return false;  
        }  
    }  
  
}  

prev_permutation es similar a la implementación, es decir, búsqueda inversa

3. Utilice next_permutation

Considere la pregunta, ¿cuál es la siguiente secuencia de la secuencia {a, d, c, e, b}? Utilice el análisis anterior para obtener la respuesta y verificarla con el código.

Aquí utilizo matrices y vectores para representar secuencias, y uso next_permutation para obtener la siguiente secuencia (entorno de compilación: Dev-C ++):

#include <cstdlib>  
#include <iostream>  
#include <algorithm>  
#include <vector>  
  
using namespace std;  
  
void TestArray()   
{
    
      
    char chs[] = {
    
    'a', 'd', 'c', 'e', 'b'};  
    int count = sizeof(chs)/sizeof(char);  
      
    next_permutation(chs+0, chs + count);  
      
    printf("TestArray:\n");  
    for(int i = 0; i < count; i++) {
    
      
            printf("%c\t", chs[i]);  
    }  
      
    printf("\n");  
}  
  
void TestVector()  
{
    
      
     char chs[] = {
    
    'a', 'd', 'c', 'e', 'b'};  
     int count = sizeof(chs)/sizeof(char);  
     vector<char> vChs(chs, chs + count);  
       
     next_permutation(vChs.begin(), vChs.end());  
       
     printf("TestVector:\n");  
     vector<char>::iterator itr;  
     for(itr = vChs.begin(); itr != vChs.end(); itr++) {
    
      
             printf("%c\t", *itr);  
     }  
     printf("\n");  
}  
  
int main(int argc, char *argv[])  
{
    
      
    TestArray();  
    printf("\n");  
    TestVector();  
      
    system("PAUSE");  
    return EXIT_SUCCESS;  
}  

4. Resumen

Es muy conveniente usar next_permutation y prev_permutation para encontrar permutaciones y combinaciones, pero recuerde incluir el archivo de encabezado #include.

Aunque la última permutación no tiene la siguiente permutación, usar next_permutation devolverá falso, pero después de usar este método, la secuencia se convertirá en la primera de la secuencia del diccionario, por ejemplo, cba se convierte en abc. Lo mismo es cierto para prev_permutation.

Supongo que te gusta

Origin blog.csdn.net/weixin_43743711/article/details/115180065
Recomendado
Clasificación