正整数分解-深度搜索优先DFS 递归函数实现

news/2024/7/20 21:04:01 标签: 深度优先, 蓝桥杯, 算法, c++

正整数分解

题目编号:Exp08-Basic01,GJBook3-12-05

题目名称:正整数分解

题目描述:正整数n,按第一项递减的顺序依次输出其和等于n的所有不增的正整数和式。


输入:一个正整数n(0<n≤15)。

输出:每行输出如样例所示,和等于n的不增正整数和式,数字和运算符间无符号,最后一行结尾有一个回车换行符。
 

样例:

输入:
4
输出:
4=3+1
4=2+2
4=2+1+1
4=1+1+1+1

这道题虽然看上去很简单,但是实际上也很简单(误)

深度优先搜索(DFS,Depth-First Search)是搜索的手段之一。它从某个状态开始,不断地转移状态直到状态无法转移,然后退到前一步的状态,继续转移到其他状态,如此不段重复,直到找到最终的解。
如求解本题,首先在数组内填入适当的数字,然后继续在下一个位置填入符合题目要求的数字,如此继续下去。如果发现某个数字下面不能再填入数字了,则将数组打印输出,随后继续回到上一个数字搜索其他情况。
跟据深度优先搜索的特点,采用递归函数实现比较简单
下面我们来看一下求解本题的思路:
题目要求, 第一项递减 的顺序依次输出其和等于n的所有 不增 的正整数和式 ,其中关键字已标红
通过下面的代码来实现
void dfs(int x, int y,int i)//x为要分解的总量,y为最大值,i为数组下标
{
	if (x <= y)//此时满足题意,可以直接打印输出
	{
		a[i] = x;
		Print(i);
	}
	for (int z = 1;z < x;z++)
	{
		if (x - z <= y)
		{
			a[i] = x - z;
			dfs(z, x - z, i + 1);
		}
	}
}

dfs函数有三个参数,

x代表需要进行分解操作的总量;

y表示已分解出数字的最大值;

i则保存数组下标,方便给数组元素赋值。

基于此,我们在main函数中调用DFS时以此形式    dfs(n,n-1,0),

以n=4为例     dfs(4,3,0)

进入dfs函数后(有条件的话大家可以拿着纸笔在纸上写写画画)

  1. 此时不满足4<=3,进入for循环
  2. 第一次for循环,z=1,x-z=3,此时x-z<=y, 把x-z存放到数组的第一位即a[0]
  3. 调用dfs(1,3,1),此时满足  1<=3  , 把x存到a[1],输出数组
    31

  4. 第二次for循环,z=2,   x-z=2,  此时x-z<=y,    把x-z存放到数组的第一位即a[0],因为上次在dfs循环中传入的为  dfs(z, x - z, i + 1)  ,所以实际上 i 的值不变,仍为1
  5. 调用dfs(2,2,1),此时满足   2<=2 ,  把x存到a[1],输出数组
    22
  6. 然后进入第二次for循环中的第一次for循环,此时 z=1,x=2,  x-z=1, 此时x-z<=y,把x-z存放a[1], 调用dfs(1,1,2)
  7. 此时满足1<=3,把1存到a[2],打印数组
    211

  8. 最后调用一次dfs,输出数组
    1111
  9. 游戏结束,芜湖!!!

相比之下,打印的函数就显得尤为很简单了呀
void Print(int i)//打印输出已排好的数组
{
	printf("%d=%d", n, a[0]);
	for (int j = 1;j <= i;j++)
	{
		printf("+%d", a[j]);
	}
	printf("\n");
}

综上,总代码如下
#include <iostream>
using namespace std;//DFS

int a[20];
int n;
void Print(int i)//打印输出已排好的数组
{
	printf("%d=%d", n, a[0]);
	for (int j = 1;j <= i;j++)
	{
		printf("+%d", a[j]);
	}
	printf("\n");
}

void dfs(int x, int y,int i)//x为要分解的总量,y为最大值,i为数组下标
{
	if (x <= y)//此时满足题意,可以直接打印输出
	{
		a[i] = x;
		Print(i);
	}
	for (int z = 1;z < x;z++)
	{
		if (x - z <= y)
		{
			a[i] = x - z;
			dfs(z, x - z, i + 1);
		}
	}
}

int main()
{
	scanf_s("%d", &n);
	dfs(n, n - 1, 0);
	return 0;
}


http://www.niftyadmin.cn/n/1569237.html

相关文章

排序不等式 GCJ 2008 Round1A Problem A. Minimum Scalar Product

排序不等式&#xff08;Rearrangement Inequality&#xff09;又称排序原理&#xff0c;是数学上的一种不等式。它可以推导出很多有名的不等式&#xff0c;例如&#xff1a;算术几何平均不等式、柯西不等式、切比雪夫总和不等式。 简洁的来说就是两组数对应“顺序”相乘的和 &g…

十进制转化为任意进制 C++ 递归实现

7. 十进制转换任意进制 题目编号 &#xff1a;Exp06-Enhance05&#xff0c;freshman-1022 题目名称&#xff1a;十进制转换任意进制 题目描述&#xff1a;编写程序&#xff0c;用递归方法将十进制的正整数 N 转换为 b 进制数&#xff08;2≤b≤36&#xff09;&#xff0c;其中字…

双指针算法的巧妙运用

目录 用对撞指针反转一个数组 快慢指针&#xff1a; 1.寻找链表中间节点 2.删除链表倒数第k个节点 用对撞指针反转一个数组 例&#xff1a; 输入&#xff1a;5 1 2 3 4 5 输出&#xff1a;5 4 3 2 1 #include <iostream> using namespace std;int main() {int n 0;i…

C++核心编程 程序的内存模型

温馨提示&#xff1a;本笔记配合视频食用更佳 https://www.bilibili.com/video/BV1et411b73Z?p84&spm_id_from333.1007.top_right_bar_window_history.content.clickhttps://www.bilibili.com/video/BV1et411b73Z?p84&spm_id_from333.1007.top_right_bar_window_his…

C++ 函数提高

温馨提示&#xff1a;本笔记配合视频食用更佳 https://www.bilibili.com/video/BV1et411b73Z?p95https://www.bilibili.com/video/BV1et411b73Z?p95 1.函数默认参数 在C中&#xff0c;函数的参数列表中的形参是可以有默认值的 语法&#xff1a;返回值类型 函数名 (参数…

C++类与对象--封装

https://www.bilibili.com/video/BV1et411b73Z?p99https://www.bilibili.com/video/BV1et411b73Z?p99 C面向对象的三大特性为&#xff1a;封装、继承、多态 C认为万事万物都皆为对象&#xff0c;对象上有其属性和行为 例如&#xff1a; 人可以作为对象&#xff0c;属性有姓…

C++ 类与对象--对象特性

https://www.bilibili.com/video/BV1et411b73Z?p106&spm_id_from333.1007.top_right_bar_window_history.content.clickhttps://www.bilibili.com/video/BV1et411b73Z?p106&spm_id_from333.1007.top_right_bar_window_history.content.click 目录 1.构造函数与析构函…

linux常见文件夹名称及作用

在Linux系统中&#xff0c;有许多常用的目录&#xff0c;每个目录都有其特定的作用和用途。以下是一些常见的Linux文件夹及其作用的示例&#xff1a; ---命令&#xff08;公共 程序&#xff09; /bin/&#xff1a;存放系统命令&#xff08;二进制文件&#xff09;&#xff0c;…