【组合问题】-因子分解_dfs分解-程序员宅基地

技术标签: 算法  深度优先  信息学奥赛-搜索专题  

信息学奥赛一本通(C++版)在线评测系统


解题思路:

(1)将一个数分解为所有素因子的乘积,如果因子有相同的话,需要写成a的b次方的格式

(2)第一想法,将目标值n先从因子2开始枚举,开始试除,如果可以被整除的话,那么2就是他的因子,然后继续将目标值缩小为n/2,继续试除,一直到n不能被2整除的话,枚举3是否能整除,依次类推

(3)每一个商都需要进行分解,层层递进,一直到商为素数,那么可以利用递归深搜的解法,一直将目标值缩小,继续下一层递归

(4)设置函数dfs(start,num),start表示开始试除的因子,num为目标值,想想递归的出口,如果这个数不是质数,那么肯定能被2~sqrt(num)之间的数整除,因子都是成对出现的,题目要求从小到大排列,那么如果商还是合数,必然会被下一次分解,如果是质数,那么在2~sqrt(num)中已经没有因子了,所以出口在start>sqrt(num),最后一个因子记得也要收集起来

 试想一下,如果出口是start>num,那么11必然也会被11整除,最后的商变为了1,即最后收集的结果因子是1,很明显不符合题目要求,所以出口为start>sqrt(num)(仔细体会)

(5)递归的可行性方案为,当num%start==0,说明start是一个因子,收集结果,目标值缩小num=num/start,如果不能被整除,枚举下一个因子 start++,然后继续递归

(6)将所有因子收集到ans数组中,展开最长连号的判断,如果本项和后一项相等,说明要写成a^b的格式,否则直接输出a,最后利用打标记的方法,先输出首部,再输出剩余的部分(因为涉及到*号的输出)


#include<bits/stdc++.h>
using namespace std;

int n,cnt;//cnt表示分解出来因子的数量 
int ans[110];//用来存放因子 

void dfs(int start,int num)
{
	if(start>sqrt(num)) //递归出口,当因子大于num的平方根 
	{
		ans[++cnt]=num;//将最后一个因子收集 
		return ;//结束 
	}
	
	if(num%start==0)//可行性方案,如果num被start整除了 
	{
		ans[++cnt]=start;//保存现场,将因子存入数组 
		num=num/start;//目标值缩小 
	}
	else//如果不能被整除 
	{
		start++; //枚举因子增加 
	}
	
	dfs(start,num);//继续递归 
}
int main()
{
	int res=1;//负责统计相同因子的数量 
	cin>>n;
	dfs(2,n);//从2开始枚举因子分解目标值n 
	
	bool flag=0;//打标记是否输出* 
	for(int i=1;i<=cnt;i++)//遍历结果数组 
	{
		if(ans[i]==ans[i+1])//如果本项和后一项相等 
		res++;//数量加1 
		else
		{
			if(flag==0)//如果输出的是首部 
			{
				if(res!=1)//如果数量不为1 
				{
					cout<<ans[i]<<"^"<<res;//输出因子 
				}
				else//输入数量为1 
				{
					cout<<ans[i];//输出因子 
				}
				flag=1;//标记取消 
			}
			else//如果输出首部了 
			{
				if(res!=1)
				{
					cout<<"*"<<ans[i]<<"^"<<res;//如果数量不为1 
				}
				else
				{
					cout<<"*"<<ans[i];//如果数量为1 
				}
			}
			
			res=1;//计数器归1 
		}
	}
	return 0;
}

解法2:递归

(1)可以设置函数dfs(start ,num,cnt);分别表示试除的因数,还有目标值,和该因数的数量,从2开始枚举,该递归函数的出口一定是num=1,因为不管最后是质数还是合数,因数一直会增加,比如22,分解为2*11,当num=11,start=11的时候,结果为1,就可以退出了,表示没有因数了。

(2)因为cnt已经记录了该因数的数量,所以只要对cnt进行分类讨论即可,当cnt>1的时候,输出a的b次方的格式,cnt=1的时候,直接输出因子

(3)可行性方案为:如果当前start能整除num,那么让他一直除下去

(4)一旦不再被start整除的话,那么开始输出start的因数,同理根据cnt的数量开始判断,并且开始枚举下一个因数,start+1,记得cnt清零

(5)递归函数每一层都会形成新的局部变量,尤其全局变量的应用,应仔细思考


#include<bits/stdc++.h>
using namespace std;

bool flag;//用来标记是否输出* 

//start表示试除的因子,num表示目标值,cnt表示当前因子的数量
void dfs(int start,int num,int cnt) 
{
	if(num==1)//如果目标值为1,结束递归 
	{
		if(cnt>1)//如果当前因子的数量大于1 
		{
			if(flag==1)
			cout<<"*";
			
			cout<<start<<"^"<<cnt;//输出a的b次方的格式 
			flag=1;
		}
		else if(cnt==1)//如果当前因子等于1 
		{
			if(flag==1)
			cout<<"*";
			
			cout<<start;//输出该因数 
			flag=1;
		}
		return ;//递归结束 
	}
	
	if(num%start==0)//如果当前能被start整除 
	{
		dfs(start,num/start,cnt+1);//一直除下去 
	}
	else//如果不能被start整除 输出start这个因数 
	{
		if(cnt>1) //根据cnt的数量确定输出格式 
		{
			if(flag==1)
			cout<<"*";
			
			cout<<start<<"^"<<cnt;
			flag=1;
		}
		else if(cnt==1)
		{
			if(flag==1)
			cout<<"*";
			
			cout<<start;
			flag=1;
		}
		
		dfs(start+1,num,0);//将因子+1,继续试除,cnt归零 
	}
}

int main()
{
	int n;
	cin>>n;
	
	dfs(2,n,0);//从2开始试除,目标值是n 
	return 0;
} 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_60869516/article/details/127222772

智能推荐

android关于自定义Dialog中布局match_parent 属性 失效的问题_android dialog 布局 match_parent 无效-程序员宅基地

文章浏览阅读1.9k次。dialog如果没有设置style,那么系统会主动设置一个style,这个style中的decorview会存在padding,所以导致match_parent无效1.方法一dialog.show();//在show之后修改,必须这样否则无效,没看源码具体原因不知道Window window =dialog.getWindow();if (window == null) {..._android dialog 布局 match_parent 无效

vue3+vite+ts的项目打包后使用静态资源dist用5+app打包成APP_vite vue ts 转 app-程序员宅基地

文章浏览阅读256次,点赞10次,收藏2次。使用app在真机上安装完成后,进入首页后登录时遇到了连不上后端api的问题,在处理完跨域的问题后,发现因为发布app时 vue开发模式下配置的跨域是无效的,打包后会找不到接口。使用HBuildeX创建5+app项目,然后删除。并将vue3打包出来的dist文件夹中的。全部内容复制到5+app项目中;_vite vue ts 转 app

毕设开源 基于Python的南京二手房数据采集及可视化分析-程序员宅基地

文章浏览阅读734次,点赞6次,收藏10次。首先通过爬虫采集链家网上所有南京二手房的房源数据,并对采集到的数据进行清洗;然后,对清洗后的数据进行可视化分析,探索隐藏在大量数据背后的规律;最后,采用一个聚类算法对所有二手房数据进行聚类分析,并根据聚类分析的结果,将这些房源大致分类,以对所有数据的概括总结。通过上述分析,我们可以了解到目前市面上二手房各项基本特征及房源分布情况,帮助我们进行购房决策。Python网络爬虫技术RequestsPython数据分析技术NumpyMatplotlibPandask-means聚类算法。

Android开发,Kotlin的了解与学习(三)-----流程控制语句_break' or 'continue' jumps across a function or a -程序员宅基地

文章浏览阅读1.4k次。这一章主要讲一讲Kotlin中 for if when等的使用方法_break' or 'continue' jumps across a function or a class boundary

详细讲解局部变量、全局变量、静态变量三种类型_静态局部变量 pub-程序员宅基地

文章浏览阅读391次。你需要明白的java基础知识之一(变量)_静态局部变量 pub

python:插值查找法_插值查找代码-程序员宅基地

文章浏览阅读5.9k次。插值算法python实现_插值查找代码

随便推点

React脚手架介绍和Demo_脚手架demo是什么-程序员宅基地

文章浏览阅读256次。React脚手架生成代码和Demo_脚手架demo是什么

插画人物怎么画?人体动态结构怎么画?_人体体块怎么画-程序员宅基地

文章浏览阅读3.2k次。动漫人物怎么画?人体动作怎么画?有多少绘画新手都是喜欢收藏大量人体图文或是人体视频教程,但是从来都从来都没有认真的练习过的,收藏夹可不会让你画技提升,究其原因还是因为干货缺少了理论上的指导,导致众多小可爱知其然不知其所以然。为此今天就分享了一套人体动态练习图,搭配讲解食用你还怕学不会吗?顺便推荐大家可以搜一下:灵猫课堂,或者打开手机微信,添加好友框内搜索:灵猫课堂,一键关注,学习无忧!上面..._人体体块怎么画

C语言字符串操作总结大全(超详细)_复制指定长度字符串-程序员宅基地

文章浏览阅读513次。1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, p1) 附加字符串 strncat(p, p1, n) 附加指定长度字符串 strlen(p) 取字符串长度 strcmp(p, p1) 比较字符串 strcasecmp忽略大小写比较字符串strncmp(p, p1, n) 比较指定长_复制指定长度字符串

宝塔的防火墙是什么?有什么作用呢?_宝塔系统防火墙是什么防护-程序员宅基地

文章浏览阅读1.4w次。宝塔想必大家一定很熟悉了,用过服务器的都知道。那今天给大家介绍下宝塔的防火墙。宝塔面板网站防火墙是基于nginx/apache模块开发的一套应用层防火墙,能有效阻止大部分渗透攻击,且提供高度自由的规则自定义功能,为站点加一道铜墙铁壁。主要目的是从源头阻止站点被挂马的事情发生。目前宝塔官网和官方论坛一直都在使用宝塔网站防火墙,效果良好。宝塔面板防火墙是一个防火墙程序,用于在宝塔面板中防御服务器外来攻击使用的。根据环境服务软件的不同,分为nginx防火墙和apache防火墙。宝塔面板防火墙其实管理的是操_宝塔系统防火墙是什么防护

Node+Vue毕设网上约会网站(程序+mysql+Express)-程序员宅基地

文章浏览阅读349次,点赞4次,收藏8次。随着网络技术的不断进步和社会节奏的加快,越来越多的单身人士倾向于通过在线渠道来结识新朋友或寻找潜在的伴侣,这一现象推动了网上约会网站的迅猛发展。本项目将采用HTML、CSS、JavaScript、Vue等前端技术结合Node.js、Express等后端技术,以及MySQL数据库,通过VSCode和Navicat等开发工具,构建一个功能完善、操作简便的网上约会网站,旨在为现代单身人士提供一个优质的交友平台。此外,强大的网上约会网站还能促进社会交往方式的创新,推动经济增长,提升社会整体的社交网络水平。

ubuntu目录分析_ubuntu opt目录-程序员宅基地

文章浏览阅读2.1k次。在Ubuntu系统中,/usr目录是一个重要的目录,它包含了系统的用户程序和数据。这只是一些常见的文件夹,实际上还有更多的文件夹和子目录。比较重要的有/etc,存放系统配置,proc我对虚拟文件系统不太了解,/usr下各目录的解释。_ubuntu opt目录

推荐文章

热门文章

相关标签