蓝桥杯:数的划分 记忆搜索解法

蓝桥杯:数的划分 记忆搜索解法

问题描述

一个正整数可以划分为多个正整数的和,比如n=3时:
  3;1+2;1+1+1;
  共有三种划分方法。
  给出一个正整数,问有多少种划分方法。
输入格式
  一个正整数n
输出格式
  一个正整数,表示划分方案数
样例输入

3

样例输出

3

数据规模和约定
  n<=100

思路

  • 任何正整数 n 都可以拆分为 n 个 1 相加,那么可以得到最长的相加的序列是 n 个 1 相加
  • 任何正整数 n 都可以拆分为 1 个 n 加上 1 个 0,那么可以得到最短的序列是 n + 0

n 个 1 对应的情况是:每一份划分的值不大于 1
n 加 0 对应的情况是:每一份划分的值为 n

一次递归分析:

如果我们想将 x 分割为若干份,每一份分割的值 <= max,那么有两种情况:

  1. x >= max 时: 又有两种情况
    1. 如果其中一份分割的值为max (这一份的分法已经确定),剩下的所有分割之和为 x-max,那么问题就被分割为子问题:即求解 【x-max 可以被分割成值不超过 max 的若干分割块】的分法数目
    2. 如果每一份分割的值都小于max,那么问题的解就变成:【将x分割为若干份,每一份分割的值不超过max-1】的分发数目 x >= max 情况的解就是上面两个情况的解之和
  2. x < max 时: 【将 x 分割为若干分,每一份分割的值不超过max】的分法的数目 = 【将x分割为若干分,每一份分割的值不超过 x 】 的分法的数目,于是问题变为求解【将x分割为若干分,每一份分割的值不超过 x 】的分法数目

结束条件

  • 如果将 n 分割,每一份分割块的值不超过1,即 n 个 1 相加,有且只有一种情况,返回1
  • 如果将 0 分割,每一份分割块的最大值任意,那么还是 一个 0 ,返回1
  • 如果 分割块的最大值 = 1,那么就是 n 个 1 加和,也是返回1

AC完整代码

  • 直接递归,会有一个样例过不了,就是100,会超时一点,故用记忆搜索优化一下
#include <iostream>
#include <cstring>

using namespace std;

int res[114][114] = {0};

// 返回将n分割成若干块,每一块的值<=max 的分法数目
int num(int x, int max)
{
	if(x==1 || max==1 || x==0)
	{
		return 1;
	}
	
	if(x >= max)
	{
		int r1;
		if(res[x][max-1])
		{
			r1 = res[x][max-1];
		}
		else
		{
			r1 = num(x, max-1);
			res[x][max-1] = r1;
		}
		
		int r2;
		if(res[x-max][max])
		{
			r2 = res[x-max][max];
		}
		else
		{
			r2 = num(x-max, max);
			res[x-max][max] = r2;
		}
		
		return r1 + r2;
	}
	else
	{
		if(res[x][x])
		{
			return res[x][x];
		}
		else
		{
			int r = num(x, x);
			res[x][x] = r;
			return r;
		}
	}
}

int main()
{
	int n;
	cin>>n;
	
	cout<<num(n, n)<<endl;
	
	return 0;
}



发布了38 篇原创文章 · 获赞 1 · 访问量 494

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/104010091
今日推荐