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;
}