题目描述 Description
给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1~MAX之间的每一个邮资值都能得到。
例如,N=3,K=2,如果面值分别为1分、4分,则在1分~6分之间的每一个邮资值都能得到(当然还有8分、9分和12分);如果面值分别为1分、3分,则在1分~7分之间的每一个邮资值都能得到。可以验证当N=3,K=2时,7分就是可以得到的连续的邮资最大值,所以MAX=7,面值分别为1分、3分。
输入描述 Input Description
N和K
输出描述 Output Description
每种邮票的面值,连续最大能到的面值数。数据保证答案唯一。
样例输入 Sample Input
3 2
样例输出 Sample Output
1 3
MAX=7
这是一道经典的dfs套dp的题目。在深搜的时候要不断的动态决定搜索区域。也可以用迭代加深搜索。不过感觉还是dp简单。
#include <iostream>
#include <cstdio>
using namespace std;
int n,m,maxans=0;
int a[100],ans[100];
int Dp(int l)
{
int i=1;
int f[1000];f[0]=0;f[1]=1;
while(f[i]<=n)
{
f[++i]=n+1;
for(int j=1;j<=l;j++)
{
if(a[j]<=i)
{
if(f[i]>f[i-a[j]]+1)
f[i]=f[i-a[j]]+1;
}
}
if(f[i]==n+1)return i-1;
}
return i;
}
void dfs(int cur)
{
if(cur==m)
{
int tmp=Dp(m);//搜索选定m种邮票面值后进行Dp得出所能达到最大面值
if(tmp>=maxans)
{
for(int i=1;i<=cur;i++)
{
ans[i]=a[i];
maxans=tmp;
}
}
return;
}else{
int tmp=Dp(cur)+1;
for(int i=a[cur]+1;i<=tmp;i++)//我们每次加进的邮票面值都要比上一次的大,这样既不会重复也一定能扩展,要小于所能拼出的最大值+1.我们的目标是每次不遗漏的加1
{
a[cur+1]=i;
dfs(cur+1);
}
}
}
int main()
{
cin>>n>>m;
a[1]=1;
dfs(1);
for(int i=1;i<=m;i++)
printf("%d ",ans[i]);
printf("\n");
printf("MAX=%d\n",maxans);
return 0;
}