PAT回溯:连续因子(回溯 + dp)

L1-006 连续因子 (20 分)
一个正整数 N 的因子中可能存在若干连续的数字。例如 630 可以分解为 3×5×6×7,其中 5、6、7 就是 3 个连续的数字。给定任一正整数 N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。

输入格式:
输入在一行中给出一个正整数 N(1<N<2
​31
​​ )。

输出格式:
首先在第 1 行输出最长连续因子的个数;然后在第 2 行中按 因子1因子2……*因子k 的格式输出最小的连续因子序列,其中因子按递增顺序输出,1 不算在内。

输入样例:
630
输出样例:
3
567

【思路】
一开始,觉得这种拆分因子的题应该纯递归可以解决,但后来发现,由于一个整数可以有多种拆分,并且看到题目中说,按最小的连续因子序列输出,所以我转变了思路,用回溯法求解。

回溯部分好理解,就是穷举每一个可能的数作为因子,如果val == 1了,那么说明到达边界,此时就要看看这时的因子序列中,连续因子的数目是多少,如果比之前存的最大值大,那么就要修改!这里我用了一点dp的思维求最大连续因子个数

代码(最后一个测试点愣是超时,没过,去除掉所有素数,还是超时,反正大概思路是这样):

/*
思想:dfs算了 
*/
#include<iostream>
using namespace std;

const int maxn = 60;
int x[maxn];
int l = 1;
int dp[maxn];
int res[maxn];
int mi = 0;
int ans = 0;

bool IsPrime(int x)
{
	for(int i = 2;i * i <= x;i++)
	{
		if(x % i == 0)
			return false;
	}
	return true;
}

void dfs(int val)			//val表示当前的值, len表示当前连续因子的长度 
{
	if(val == 1)
	{
		//找到连续因子,用dp 
		dp[1] = 1;
		for(int i = 2;i < l;i++)
		{
			if(x[i] - x[i - 1] != 1)
				dp[i] = 1;
			else
				dp[i] = dp[i - 1] + 1;
		}
		int max_res = dp[1];
		int max_i = 1;
		for(int i = 2;i < l;i++)
		{
			if(max_res < dp[i])		//这里之前出了一点bug 
			{
				max_res = dp[i];
				max_i = i;
			}
		}
		if(max_res > ans)
		{
			ans = max_res;
			mi = max_i;
			for(int i = mi - ans + 1, j = 1;i < l;i++, j++)
			{
				res[j] = x[i];
			}
		}
		return ; 
	}
	//枚举所有可能的因子 
	for(int i = 2;i <= val;i++)
	{
		if(val % i == 0)
		{
			x[l++] = i;
			dfs(val / i);
			l--;
		}
	}
}

int main()
{
	int n;
	cin >> n;
	if(IsPrime(n))			//将所有质数都剪枝了,提速
	{
		cout << 1 << endl;
		cout << n << endl;
	}
	else
	{
		dfs(n);
		cout << ans << endl;
		for(int j = 1;j <= ans;j++)
		{
			if(j != ans)
				cout << res[j] << "*";
			else
				cout << res[j];
		}
		cout << endl;	
	}
	return 0;
}

【运行结果】
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_40163242/article/details/88171273
今日推荐