Algoritmo Serie preliminar 1-Búsqueda Enumeración de la primera búsqueda en profundidad

Creo que todo el mundo ha aprendido el algoritmo de enumeración. Si lo ha aprendido, ¡continúe aprendiendo de Jun Jiao!

En primer lugar, mire una pregunta ~

Tema 1: Arreglo completo

  • Descripción
    Introduzca n, emite todas las permutaciones de 1 an que no se repiten, es decir, todas las permutaciones de n.
  • Análisis
    Obviamente, este problema no se puede resolver con la enumeración de bucle for, porque necesita usar un "n-reciclaje", y n es una variable, por lo que no se puede usar el algoritmo de enumeración.
    ¿Cómo resolver este problema? Todo el mundo debería pensar que si el número de capas de bucle es indefinido, se puede realizar mediante recursividad. Este es uno de los objetivos de nuestro algoritmo de búsqueda en profundidad (dfs).
    En el proceso de recursividad, el algoritmo dfs usa un bucle for para enumerar, es decir, el número de capas del bucle for aquí está determinado por recursividad, en lugar de escribir una por una.
  • Código
#include <bits/stdc++.h>
using namespace std;
bool vis[11]; // 假设n最大为10,vis[i]表示第i个数在当前这个排列中是否被用过
int n, a[11]; // 表当前排列的结果 
void dfs(int stp) {
    
    	// stp是step的缩写,表示现在已经枚举到了第几步(所谓的第几层循环) 
	if (stp == n + 1) {
    
    	// 当n层循环都枚举完后,输出当前结果并且结束dfs函数 
		for (int i = 1; i <= n; ++i) {
    
    
			cout << a[i] << ' ';
		}
		cout << '\n'; // 不要忘记排列之间要用换行隔开 
		return ;
	}
	for (int i = 1; i <= n; ++i) {
    
    	// 枚举所有数,找到符合条件的数(没有被用过),然后放到当前数位上 
		if (!vis[i]) {
    
    
			vis[i] = 1;	a[stp] = i; // 先放到当前数位上,继续枚举,然后尝试其他数,这样的过程就是一个回溯算法 
			dfs(stp + 1);
			vis[i] = 0;
		}
	}
}
int main() {
    
    
	cin >> n;
	dfs(1); // 从第1个数开始枚举 
	return 0;
}

El comentario ya es muy claro y el Sr. Konjac ya no hablará más sobre este tema.
Recordatorio cálido de Konjac Jun : durante el proceso de búsqueda y enumeración, podemos podar y optimizar el proceso de acuerdo con la naturaleza de la pregunta (hablaremos de ello en las próximas lecciones). Pero en la mayoría de los problemas, la complejidad de tiempo de dfs excederá, por lo que es necesario determinar el número total de estados del problema antes de buscar.
Aquí hay una pregunta de práctica para todos ~

Tema 2: Pollo asado

  • Fondo
    cerdo hanke tiene un pollo
  • Descripción Al
    cerdo Hanke le gusta comer pollo asado (este es el mismo animal, ¿por qué es tan urgente freírlo?) Hanke come pollo muy especial, ¿por qué es especial? Como tiene 10 tipos de ingredientes (mostaza, comino, etc.), cada ingrediente puede poner de 1 a 3 gramos, la delicia de cualquier pollo asado es la suma de todos los ingredientes.
    Ahora, Hanke quiere saber, si le das una delicia, imprima todos los esquemas coincidentes de estos 10 ingredientes
  • Formato de entrada :
    una línea, n <= 5000
  • Formato de salida : la
    primera línea, el número total de programas, la
    segunda línea hasta el final, 10 números, lo que indica que la calidad de cada ingrediente está
    ordenada en orden lexicográfico.
    Si no hay ningún método que cumpla con los requisitos, solo envíe un "0" en la primera línea
  • Entrada de ejemplo # 1 :
    11
  • Ejemplo de salida # 1 :
    10
    1 1 1 1 1 1 1 1 1 2
    1 1 1 1 1 1 1 1 2 1
    1 1 1 1 1 1 1 2 1
    1 1 1 1 1 1 2 1 1 1
    1 1 1 1 1 2 1 1 1 1 1
    1 1 1 1 2 1 1 1 1 1
    1 1 1 2 1 1 1 1 1 1
    1 1 2 1 1 1 1 1 1 1
    1 2 1 1 1 1 1 1 1 1
    2 1 1 1 1 1 1 1 1 1
  • Análisis
    Obviamente, esta pregunta se puede enumerar con diez ciclos, pero hemos aprendido los gl más básicos, ¿por qué usar diez ciclos de enumeración? Konjai Jun aquí le da una plantilla, por favor termine de escribir el título y puede enviarlo aquí .
#include <bits/stdc++.h>
using namespace std;
int n, ans1, ans2[10000][10], arr[10], sum;
void dfs(int stp, int now) {
    
    
	// 请继续完成这个函数~ 
}

int main() {
    
    
	cin >> n; dfs(1, 0);
	cout << ans1 << '\n';
	for (int i = 1; i <= ans1; ++i) {
    
    
		for (int j = 1; j <= 10; ++j) {
    
    
			cout << ans2[i][j] << ' ';
		}
		puts("");
	}
	return 0;
}

  • Interpretaciones Entrada de
    efecto de título
    a n, cuántos tipos de programas dan como resultado diez y el número de n, el orden no se considera dos tipos y genera cada opción.
    Ideas para resolución de problemas
    Comenzando desde el primer nivel (el primer elemento de la matriz), registre la suma de la matriz actual. Continúe bajando dfs, cuando finalmente alcanza el punto crítico, se juzga la condición y se registran los datos registrados y los datos almacenados que cumplen con las condiciones. Si no está satisfecho, vuelva al nivel anterior.
    Código
#include <bits/stdc++.h>
using namespace std;
int n, ans1, ans2[10000][10], arr[10], sum;
void dfs(int stp, int now) {
    
    
	if (stp > 10) {
    
    
		if (now == n) {
    
    
			++ans1;
			for (int i = 1; i <= 10; ++i) {
    
    
				ans2[ans1][i] = arr[i];
			}
		}
		return ;
	}
	for (int i = 1; i <= 3; ++i) {
    
    
		if (now + i > n) {
    
    
			break;
		}
		arr[stp] = i;
		dfs(stp + 1, now + i);
		arr[stp] = 0;
	} 
}
int main() {
    
    
	cin >> n; dfs(1, 0);
	cout << ans1 << '\n';
	for (int i = 1; i <= ans1; ++i) {
    
    
		for (int j = 1; j <= 10; ++j) {
    
    
			cout << ans2[i][j] << ' ';
		}
		puts("");
	}
	return 0;
}

Después de aprender esto, todos deberían haber descubierto un pequeño patrón ~

Enumere el marco dfs básico para todos ~

void dfs(目前状态) {
    
    
	判断边界
	尝试每一种可能,跳出可以继续的 {
    
    
		继续搜索,尝试下一步 
	} 
}

¡Por supuesto, la enumeración no tiene que usar un bucle for! Aquí hay un ejemplo para todos, espero que todos puedan entenderlo ~

Tema 3: Cuadrado mágico de orden n

  • Problema
    Ingrese n y obtenga una solución del cuadrado mágico de n orden.
  • Ideas para resolver problemas
    Obviamente, los amigos que han aprendido los cuadrados mágicos pensarán en aquellos que no pueden usar el "método del rábano" (homónimo) para verlo aquí .
  • Código
#include <bits/stdc++.h>
using namespace std;
int n, a[45][45];
void dfs(int x, int y, int now) {
    
    	// 目前坐标和下一步要填的数
	if (now > n * n) {
    
    	// 所有数都填完了,输出,然后结束dfs函数 
		for (int i = 1; i <= n; ++i) {
    
    
			for (int j = 1; j <= n; ++j) {
    
    
				cout << a[i][j] << ' ';
			}
			cout << '\n';
		}
		return ;
	}
	// 直接模拟即可
	if (x == 1 && y != n) {
    
    
		a[n][y + 1] = now;
		dfs(n, y + 1, now + 1);
	} else if (y == n && x != 1) {
    
    
		a[x - 1][1] = now;
		dfs(x - 1, 1, now + 1);
	} else if (x == 1 && y == n) {
    
    
		a[x + 1][y] = now;
		dfs(x + 1, y, now + 1);
	} else {
    
    
		if (a[x - 1][y + 1] == 0) {
    
    
			a[x - 1][y + 1] = now;
			dfs(x - 1, y + 1, now + 1);
		} else {
    
    
			a[x + 1][y] = now;
			dfs(x + 1, y, now + 1);
		}
	}
}
int main() {
    
    
	cin >> n;
	a[1][(n + 1) / 2] = 1; // 特殊处理1 
	dfs(1, (n + 1) / 2, 2);
	return 0;
} 

Al ver esto, ¿ya se ha ocupado de los problemas básicos de dfs? Si lo encuentra útil, ¡continúe esperando el segundo capítulo de Konjac!

Supongo que te gusta

Origin blog.csdn.net/yueyuedog/article/details/113067647
Recomendado
Clasificación