11 Ejercicio 2.8 Permutación completa de salida (preguntas de programación) [Conjunto de temas "Estructura de datos (2.ª edición)" de la edición de la Universidad de Zhejiang de la PTA]

11 Ejercicio 2.8 Permutación completa de salida (preguntas de programación) [Conjunto de temas "Estructura de datos (2.ª edición)" de la edición de la Universidad de Zhejiang de la PTA]

1. Enlace al título original

Ejercicio 2.8 Permutación completa de salida (pintia.cn)

2. Descripción del tema

Escriba un programa para generar el nn anteriorPermutación completa de n enteros positivos (n < 10 n<10norte<10 ), y pasó 9 casos de prueba (es decir,nnn del 1 al 9) observarnnEl tiempo de ejecución del programa cuando n aumenta gradualmente.

Formato de entrada:

La entrada da un entero positivo nnnorte< 10 < 10<10 )。

Formato de salida:

salida 1 a nnLa permutación completa de n . Cada permutación ocupa una línea, sin espacios entre números. El orden de salida del arreglo es el orden lexicográfico, es decir, la secuenciaa 1 , a 2 , ⋯ , an { a_1, a_2, \cdots, a_n }a1,a2,,anClasificado en secuencia b 1 , b 2 , ⋯ , bn { b_1, b_2, \cdots, b_n }b1,b2,,bnAntes, si k existek使得a 1 = segundo 1 , ⋯ , ak = bk a_1=b_1, \cdots, a_k=b_ka1=b1,,ak=bkY ak + 1 < bk + 1 a_{k+1}<b_{k+1}ak + 1<bk + 1

Muestra de entrada:

3

Salida de muestra:

123
132
213
231
312
321

3. Consulte la respuesta

responde una

#include<stdio.h>
int a[9];
void arrange(int m, int n){
    
    
	int i,j,num;
	if(m==n){
    
    
        for(i=0;i<n;i++)
            for(j=i+1;j<n;j++)
                if(a[i]==a[j])
                    return;
        for(i=0;i<n;i++)
            printf("%d",a[i]);
        printf("\n");
	}
	else{
    
    
		for(num=1;num<=n;num++){
    
    
            a[m]=num;
            arrange(m+1, n);
		}
	}
}
int main(){
    
    
    int n;
    scanf("%d", &n);
    arrange(0, n); 
    return 0;
}

responder dos

#include<stdio.h>
int a[9];
void arrange(int m, int n){
    
    
	int i,j,num;
	if(m==n){
    
    	
		for(i=0;i<n;i++)
			printf("%d",a[i]);
		printf("\n");
	}
	else{
    
    
		for(num=1;num<=n;num++){
    
    
			for(j=0;j<m;j++)
				if(a[j]==num)break;
			if(j==m){
    
    
				a[m]=num;
				arrange(m+1, n);
			}
		}
	}
}
int main(){
    
    
    int n;
    scanf("%d", &n);
    arrange(0, n); 
    return 0;
}

responder tres

#include <stdio.h>

int visited[10]={
    
    0};
int  list[10];
void dfs(int n,int m){
    
    
    int i;
	if(m==n+1){
    
    
		for(int i=1;i<=n;i++)
			printf("%d",list[i]);
		printf("\n");
	}
	else{
    
    
		for(i=1;i<=n;i++){
    
    
			if(!visited[i]){
    
    
				list[m]=i;	
				visited[i]=1;
				dfs(n,m+1);	
				visited[i]=0;
			}
		}
	}
}
int main(){
    
    
	int n;
	scanf("%d", &n);
	dfs(n,1);
	return 0;
} 

respuesta cuatro

#include <stdio.h>
int a[10];
void shift( int l, int i);
void shiftb( int l, int i );
void Per( int l, int r );
int main(){
    
    
    int n, i;
    scanf("%d", &n);
    for (i=0; i<=n; i++) a[i] = i;
    Per(1, n);
    return 0;
}
void shift( int l, int i){
    
    
     int j, t=a[i];
     for (j=i; j>l; j--)
         a[j]=a[j-1];
     a[l] = t;
}
void shiftb( int l, int i ){
    
    
     int j, t=a[l];
     for (j=l; j<i; j++)
         a[j] = a[j+1];
     a[i] = t;
}
void Per( int l, int r ){
    
    
     int i;
     if (r==l) {
    
    
        for (i=1; i<=r; i++) printf("%d", a[i]);
        printf("\n");
     }
     else {
    
    
          for (i=l; i<=r; i++) {
    
    
              shift(l, i);
              Per(l+1, r);
              shiftb(l, i);
          }
     }
}

4. Ideas para resolver problemas

nn antes de enviar esta preguntaPermutación completa de n enteros positivos (n < 10 n<10norte<10 ), sinnn es un valor fijo, como 3, entonces el arreglo completo se puede realizar a través de un ciclo triple, y el método de implementación es el siguiente:

#include<stdio.h>
int main(){
    
    
	int i,j,k;
	for(i=1;i<=3;i++){
    
    
		for(j=1;j<=3;j++){
    
    
			for(k=1;k<=3;k++){
    
    
				if(i!=j&&j!=k&&i!=k)
					printf("%d%d%d\n",i,j,k);
			}
		}
	}
	return 0;
}

Pero el nn en esta preguntan es una variable Si se realiza por bucle, el número de capas del bucle es incierto, por lo que se puede realizar por recursividad. Se pueden ver tres cosas de la implementación del bucle:

  1. Cada capa de bucles selecciona un número en orden, y la recursividad de llamadas selecciona naturalmente un número en orden para cada capa de llamadas;

  2. La salida se emite cuando el bucle alcanza la última capa, y la llamada a la función recursiva, naturalmente, también se llama recursivamente a la última capa para la salida.

    //m记录当前层级,若当前层级m到达最大层级n,输出排列完毕之后的数组
    if(m==n){
          
          	
        for(i=0;i<n;i++)
            printf("%d",a[i]);
        printf("\n");
    }
    

    Al mismo tiempo, la función recursiva del arreglo completo requiere al menos dos parámetros: 1. El nivel de la llamada actual 2. El nivel más grande, es decir, la entrada nnnorte _

    //排列permutation
    void Per( int now, int n )
    
  3. Cada dígito de la salida no se repite. Si desea que la salida de cada dígito no se repita, existen cuatro algoritmos:

    • Algoritmo 1: el bucle triple anterior es para verificar la repetibilidad de cada dígito antes de generar, nn en esta preguntan es incierto, es decir, la cantidad de números es incierta. Si verifica la repetibilidad de cada dígito antes de generar la salida, debe usar un bucle doble para comparar cada dígito con cada dígito de otros dígitos. El último del algoritmo El el punto de prueba expirará.
    • Algoritmo 2: optimizar el algoritmo 1, en lugar de verificar la repetibilidad de los números al final, verifique al ingresar cada capa. Como se puede ver en el bucle triple del ejemplo anterior, cada capa del arreglo atraviesa todos los números. Por ejemplo, la primera capa del bucle atraviesa del 1 al 3, y la segunda capa del bucle también atraviesa del 1 al 3. Compruebe si el número seleccionado en el nivel actual ha aparecido en el nivel anterior. Si el número actual ha aparecido en la posición anterior, omita el número. Si el número actual no ha aparecido en la posición anterior, coloque el número en la posición de el nivel actual de la matriz.
    • Algoritmo 3: optimice aún más el algoritmo 2, no use el método transversal para verificar la repetibilidad, marque cada número usado y juzgue si el número seleccionado se puede usar marcando.
    • Algoritmo 4: primero cree una matriz int a[10];, inicialícela for (i=0; i<=n; i++) a[i] = i;, ajuste la posición de los elementos de la matriz y organice la matriz por completo, porque los valores de los elementos de la matriz se han determinado del 1 al 9, y no habrá repetición de diferentes dígitos Este es el enfoque adoptado en la respuesta de referencia a esta pregunta.

5. Respuesta detallada

Respuesta detallada

El algoritmo expirará en el último punto de prueba.

Enumere los valores posibles de cada posición, genere todas las permutaciones posibles, realice la permutación completa de los números enteros del 1 al n y use una matriz para almacenar el valor en cada posición, verifique si el número se repite antes de generar la salida, satisfará la permutación salida sin elementos repetitivos.

El análisis específico es el siguiente:

  1. Se define una matriz global int a[9];para almacenar cada permutación generada.
  2. Define una función recursiva void arrange(int m, int n);cuyo trabajo es generar permutaciones.
  3. arrangeLos parámetros de la función mindican la posición de la matriz que se está generando actualmente ne indican la longitud de la matriz que se generará.
  4. Cuando m = n, significa que se ha generado una matriz completa. En este momento, es necesario verificar si hay elementos repetidos en la matriz y, de ser así, devolverlos; de lo contrario, generar la matriz y envolverla.
  5. Cuando m<n, es necesario continuar generando el arreglo. En este momento, intente llenar la posición actual m uno por uno de 1 a n, y luego genere recursivamente el arreglo de la siguiente posición.
  6. En mainla función, primero lea la longitud de la matriz que se generará ny luego llame arrangea la función para establecer la posición inicial 0.
#include<stdio.h>
int a[9];
//m是当前层级,n是最大层级
void arrange(int m, int n){
    
    
	int i,j,num;
    //数组排列到n-1位置就排列完了,m==n排列完成输出
	if(m==n){
    
    
        //二重循环检查每位数字的重复性
        for(i=0;i<n;i++)
            for(j=i+1;j<n;j++)
                if(a[i]==a[j])//如果有数字重复则不输出
                    return;
        //如果程序执行到这里,则没有数字重复输出结果
        for(i=0;i<n;i++)
            printf("%d",a[i]);
        printf("\n");
	}
	else{
    
    
         //每一层都遍历所有的数字1至n
		for(num=1;num<=n;num++){
    
    
            a[m]=num;
            arrange(m+1, n);//递归方程计算下一个层级的数字
		}
	}
}
int main(){
    
    
    int n;
    scanf("%d", &n);
    arrange(0, n); 
    return 0;
}

Responda dos explicaciones detalladas

Optimizado sobre la base del Algoritmo 1, al seleccionar números en cada capa, recorra los números anteriores para verificar si los números se repiten.

#include<stdio.h>
int a[9];
//m是当前层级,n是最大层级
void arrange(int m, int n){
    
    
	int i,j,num;
    //数组排列到n-1位置就排列完了,m==n排列完成输出 
	if(m==n){
    
    	
		for(i=0;i<n;i++)
			printf("%d",a[i]);
		printf("\n");
	}
	else{
    
    
         //每一层都遍历所有的数字1至n
		for(num=1;num<=n;num++){
    
    
             //检查当前选择的数字num是否在前面的位置j出现过
			for(j=0;j<m;j++)
                 //如果当前选择的数字num在前面的位置j出现过则退出此循环,遍历下一个数字
				if(a[j]==num)break;
             //结束上面的循环之后,若j==m,即当前选择的数字num在之前没有出现过
			if(j==m){
    
    
				a[m]=num;
				arrange(m+1, n);//递归方程计算下一个层级的数字
			}
		}
	}
}
int main(){
    
    
    int n;
    scanf("%d", &n);
    arrange(0, n); 
    return 0;
}

Respuesta tres explicación detallada

Búsqueda en profundidad (DFS). Repita todas las combinaciones y verifique si el número se ha utilizado marcando al seleccionar el número en cada capa.

La matriz int visited[10]registra si se ha utilizado un número, lo que visited[i] = 0indica que no se ha utilizado el número i e visited[i] = 1indica que se ha utilizado el número i.

La matriz int list[10];representa la permutación resultante, donde list[i]representa iel número en la posición 1 de la permutación.

La función dfs(n, paso) indica la situación cuando la búsqueda está en la posición de paso de la matriz generada, donde n indica la longitud de la matriz (es decir, 1~n), y paso indica la posición de búsqueda actual.

Cuando step = n+1, se ha generado un arreglo completo, solo envíelo directamente.

De lo contrario, intente usar el número en 1~n como el número de la posición actual a su vez, y marque el número en la matriz visitada como ya usado, y luego busque recursivamente la siguiente posición. Al retroceder a la ubicación actual, es necesario desmarcar la matriz visitada.

#include <stdio.h>

int visited[10]={
    
    0}; //做标记,数组下标对应相应的数字,没用过记作 0, 用过后记作 1 
int  list[10];
//m是当前层级,n是最大层级
void dfs(int n,int m){
    
    
    int i;
    //m==n+1时,n个层级排列完毕
	if(m==n+1){
    
    
		for(int i=1;i<=n;i++)
			printf("%d",list[i]);
		printf("\n");
	}
	else{
    
    
         //每一层都遍历所有的数字1至n
		for(i=1;i<=n;i++){
    
    
			if(!visited[i]){
    
    //如果选择的数字没用过 
				list[m]=i;	//把它存入数组对应层级的位置
				visited[i]=1;	//标记为已使用
				dfs(n,m+1);	//进入下一层
				visited[i]=0;	//取消标记
			}
		}
	}
}
int main(){
    
    
	int n;
	scanf("%d", &n);
	dfs(n,1);	//代表从第一层开始搜索 
	return 0;
} 

Respuesta detallada cuatro

Ajuste la posición de los elementos de la matriz y organice la matriz por completo.

El análisis específico es el siguiente:

  1. define una 10matriz de enteros de longitud a[]y declara tres funciones: shift(), shiftb()y Per().
  2. En main()la función, primero ingrese un número entero ny luego use un bucle para a[]inicializar la matriz a números enteros del 1 al n.
  3. Luego llama Per()a la función.
  4. En Per()la función, si los extremos izquierdo y derecho son iguales, se emite la disposición completa actual desde 1hasta hasta .n
  5. De lo contrario, para cada uno de los rangos desde el punto final izquierdo lhasta el punto final derecho , haga lo siguiente: ri
    • Llame shift()a la función para mover el elemento th a[]en la matriz a la posición del punto final izquierdo.il
    • Opera recursivamente sobre el rango l+1alcanzado .r
    • Llame a shiftb()la función para a[]restaurar la matriz a su estado original.
#include <stdio.h>
int a[10];//程序中用不到a[0],只使用a[1]至a[9]
void shift( int l, int i);
void shiftb( int l, int i );
void Per( int l, int r );

int main(){
    
    
    int n, i;
    scanf("%d", &n);
    for (i=0; i<=n; i++) a[i] = i;
    Per(1, n);
    return 0;
}

//对数组元素进行交换,将数组a[]中第i个元素移动到左端点l的位置
void shift( int l, int i){
    
    
     int j, t=a[i];
     for (j=i; j>l; j--)
         a[j]=a[j-1];
     a[l] = t;
}
//对数组元素进行交换,将数组a[]还原到原始状态
void shiftb( int l, int i ){
    
    
     int j, t=a[l];
     for (j=l; j<i; j++)
         a[j] = a[j+1];
     a[i] = t;
}
//排列permutation
void Per( int l, int r ){
    
    
     int i;
     //如果左右两端点相同,则排列完毕,输出当前的全排列
     if (r==l) {
    
    
        for (i=1; i<=r; i++) printf("%d", a[i]);
        printf("\n");
     }
     else {
    
    
          for (i=l; i<=r; i++) {
    
    
              //将数组a[]中第i个元素移动到左端点l的位置
              shift(l, i);
              //每一层调用都会有一个for循环,for循环改变每一层函数调用的左边界位置的数字
              Per(l+1, r);
              //每一层会先改变了元素位置,内层函数执行完毕后,再把位置改变回去以便下一个循环排列
              shiftb(l, i);
          }
     }
}

6. Ampliación del conocimiento

búsqueda en profundidad

Esta pregunta revisa principalmente la recursividad. La búsqueda en profundidad primero se explicará en detalle más adelante, y aquí hay solo una breve introducción.

La búsqueda primero en profundidad (DFS, por sus siglas en inglés) es un algoritmo de recorrido de gráficos de uso común, que se implementa recorriendo nodos en el gráfico en profundidad.

Específicamente, el algoritmo DFS comienza desde un cierto nodo en el gráfico, primero visita el nodo y luego selecciona un nodo adyacente no visitado para continuar visitando hasta que se hayan visitado todos los nodos adyacentes. Si el nodo actual no tiene nodos adyacentes no visitados, retroceda al nodo anterior y continúe visitando sus nodos adyacentes no visitados hasta que se hayan visitado todos los nodos.

El algoritmo DFS se puede implementar mediante recursividad o mediante una pila. Al usar la implementación recursiva, puede usar una matriz visitada para registrar los nodos visitados para evitar visitas repetidas; al usar la implementación de pila, puede usar la función de último en entrar, primero en salir (LIFO) de la pila para guardar los vecinos no visitados de el nodo del nodo actual.

Supongo que te gusta

Origin blog.csdn.net/weixin_40171190/article/details/130048516
Recomendado
Clasificación