《DFS》《剪枝》Problem C. 买蛋糕

探讨如何使用最少数量的不同正整数来组合成任意小于等于n的正整数,通过递归搜索和剪枝策略寻找最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem C. 买蛋糕

时间限制 1000 ms
内存限制 128 MB

题目描述

  野猫过生日,大家当然会送礼物了(咳咳,没送礼物的同志注意了哈!!),由于不知道送什么好,又考虑到实用性等其他问题,大家决定合伙给野猫买一个生日蛋糕。大家不知道最后要买的蛋糕的准确价格,而只会给蛋糕估价,即要买一个不超过多少钱的蛋糕。众OIer借此发挥:能否用最少的钱币数去凑成估价范围内的所有价值,使得不管蛋糕价值多少,都不用找钱……
  现在问题由此引出:对于一个给定的n,能否用最少的不等的正整数去组成n以内(包括n)的所有的正整数呢?如果能,最少需要多少个正整数,用最少个数又有多少不同的组成方法呢?

输入数据

只有一行包含一个整数 n (1≤n≤1000)n (1≤n≤1000) 。

输出数据

一行两个数,第一个数是最少需要多少个数,第二个数是用最少个数的组成方案个数。两个答案用空格分隔。

样例输入

6

样例输出

3 2

样例说明

最少用三个数,有两种方法,分别是:1,2,3和1,2,4。
对于1,2,3有1,2,3,1+3,2+3,1+2+3;
对于1,2,4有1,2,1+2,4,1+4,2+4。

整体思路:

剪枝:基元数为m,当确定m-1个基元之后要确定第m个基元时,
首先 第m个基元>maxI且第m个基元<=n+1  当第m个基元>n+1 会出现n+1这个数无法表示  如 1 2 5(5=3+2)  4无法被表示
其次会出现3种情况
1.2*sum+1<n(sum:m-1个基元确定的最大值n(m-1));return 0 因为m基元最大是sum+1
2.sum+maxI+1>=n 会增加 sum+1-(maxI+1)+1=sum-maxI+1种情况;
3. else sum+x>=n  (n>maxI+1) x=n-sum    会增加 sum+1-(n-sum)+1=2*sum-n+2种情况;

最后呢,对所有可能的基元进行搜索即可。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#define INF 0x7FFFFFFF //int 最大值

using namespace std;

int n, m;// n:要表示1...n的数  m:最小基元数
int result = 0;
//基元为m,当确定m-1个基元时,要确定第m个基元时,
// 首先 m基元>maxI且m基元<=n+1  当m基元>n+1 会出现n+1这个数无法表示  如 1 2 5(5=3+2)  4无法被表示
//其次会出现3种情况
// 2*sum+1<n(sum:m-1个基元确定的最大值n(m-1));return 0 因为m基元最大是sum+1
//sum+maxI+1>=n 会增加 sum+1-(maxI+1)+1=sum-maxI+1中情况;
// else sum+x>=n  (n>maxI+1) x=n-sum    会增加 sum+1-(n-sum)+1=2*sum-n+2种情况;

int dfs(int num,int maxI,int sum)//num 基元的个数 maxI 最大基元, sum 基元组成的最大和 即所有基元相加
{
	if (num == m)// 要确定m基元了
	{
		if (2 * sum + 1 < n)//不能满足条件,不加情况。
			return 0;
		else if (sum + maxI + 1 >= n)
			result += sum - maxI + 1;
		else
			result += 2 * sum + 2 - n;
        return 1;
	}
    for (int i = sum + 1; i >= maxI + 1; i--)//m基元>maxI且m基元<=n+1 对于maxI+1到sum+1一次遍历
        dfs(num + 1, i,sum+i);
}
int main()
{
	cin >> n;
	//因为电脑是二进制的,所以p个数字最多能组成2^p-1  eg 1 2 4 2^3-1=7  就是1+2+4=7; 反之1...n最少需要向下取整log(n)+1个
	m = floor(log2(n)) + 1;//m就是需要使用的最少个数
	dfs(1, 0, 0);//从第一个数开始确定
	cout << m << " " << result << endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值