DFS初见 整数分解与全排列

两道题目 整数分解与全排列 初步了解了一下深度优先搜索

第一题:整数分解

DFS初见 整数分解与全排列_第1张图片

思路:当一个输入的整数被分解过后,它会产生一个剩余的数。比如7分解3会剩余4,4就成为了新的待分解的数。因此4就是7,于是分解过程是完全一致的。由是,选择递归

递归基:当剩余的数为0时,意味着分解完毕。例如7分解3剩下4,4分解4剩下0,这个时候就分解完了,可以按照需求格式打印

DFS代码部分:我们按照字典序,对于每一次的递归,都从小到大的挑选那个最小的分解数,随后把这个分解数存入一个数组中,之后在递归中挑选分解数时,需要让本次的分解数大于等于上一次的分解数,来完成去重。比如3=1+2,但到了3=2+?时,由于只剩下1可以挑选,它只能挑1,但1<2,因此就不会打印出3=2+1这个式子,以此完成去重。

随后,调用递归方法,就完成了通过确定每一个分解数的DFS

AC代码如下

//将一个正整数N分解成几个正整数相加,可以有多种分解方法 编程求出正整数N的所有整数分解式子。
#include
using namespace std;

//题目最大要求30 开30
int arr[30];

//计数器
int Count=1;

//递归里有打印要用n 开全局变量
int n;

//index : 当前分解数组arr中的索引
//current : 本次分解值
//rest : 还剩多少
void decompose(int index,int current,int rest) {
	//出口 剩余为0 结束递归 打印本次分解式
	if (rest == 0) {
		cout << n << "=";
		cout << arr[0];
		for (int i = 1; i < index; i++) {
			cout << "+" << arr[i];
		}
		if (Count % 4 != 0 && arr[index - 1] != n) {
			cout << ";";
		}
		else {
			cout << endl;
		}
		Count++;
	}
	//DFS核心代码 : 对于每一次递归 找准一个按照字典序的分解值 一直分解到结束为止
	else {
		//顶多一次分掉rest
		for (int i = current; i <= rest; i++) {
			arr[index] = i;
			//去重 :把下一次递归的分解值初值设置为i 防止例如3=1+2 和 3=2+1这样的重复
			current = i;
			//数组下标向后挪一个 传更新后的分解值 rest还剩rest-i
			decompose(index + 1, current, rest - i);
		}
	}
}

int main() {
	cin >> n;
	decompose(0,1,n);
}

第二题:全排列

DFS初见 整数分解与全排列_第2张图片 

思路:类似地,我们可以将所有待排列的元素存放入数组,每次挑选一个作为当前子列的头元素,于是就出现了一个抛开这个元素的子列,这个子列的排列过程和之前的序列的排列过程是完全一致的。由是选择递归

递归基:当数组指针指到了尾部元素索引时,说明前面的所有数已经排列完了,就剩最后一个了,于是排列结束,打印整个数组

DFS代码部分:对于每一次的递归,也即对于每一个子列,我们按照字典序由小到大地选取每次“扔”出来的元素,让这个元素插入到当前子列的头部位置,为了不打乱之后以此子列的递归,不能简单地交换这两个元素,而是需要这个元素前面的元素整体右移,再插入该元素。例如1 2 3 4 5不能简单地变成5 2 3 4 1,而应变成5 1 2 3 4这样子列1 2 3 4在下一次递归时仍有序

去重:把扔出去的元素扔回来 不然会导致这个元素在之后的排列中被换到后面去。比如 1 2 3 4,当2作为头元素但没有扔回来,之后循环中头元素会找到1,1会插入到前面来,这样就出现了1 2 3 4这个排列 但1 2 3 4在1为头元素的时候已经有了,因此产生了重复

也就是说,一个元素在被当作某些序列头元素后,不能再作为头元素出现在其他的序列里

AC代码如下:

//请编写程序输出前n个正整数的全排列(n<10)(字典序)
#include
using namespace std;

/*
把temp扔回去的意义 : 1.去重 2.字典序
*/

//arr : 本次待排序数组
//start : 本次开始索引
//end : 出口参数 start == end 结束排序 打印
void permutation(int* arr, int start, int end) {
	if (start == end) {
		//递归基 头碰到尾结束 打印数组
		for (int i = 0; i <= end; i++) {
			cout << arr[i];
		}
		cout << endl;
	}
	//DFS核心代码 : 找准一个元素,扔到最前面,剩下的继续进递归,直到出口
	else {
		//temp是本次子列找的元素 临时节点存起来防止覆盖
		int temp;
		for (int i = start; i <= end; i++) {
			temp = arr[i];
			//把temp扔到头部
			for (int j = i; j > start; j--) {
				arr[j] = arr[j - 1];
			}
			arr[start] = temp;
			//递归后面的子列
			permutation(arr, start + 1, end);
			//把temp扔回来
			for (int j = start; j < i; j++) {
				arr[j] = arr[j + 1];
			}
			arr[i] = temp;
		}
	}
}

int main() {
	int n;
	cin >> n;

	//待全排序数组arr
	int* arr = new int[n];
	//初始化数组
	for (int i = 0; i < n; i++) {
		arr[i] = i+1;
	}

	//进递归
	permutation(arr, 0, n-1);
}

你可能感兴趣的:(dfs,深度优先)