问题 1576: [蓝桥杯][算法提高VIP]邮票面值设计
时间限制: 1Sec 内存限制: 128MB 提交: 103 解决: 48
题目描述
给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤13)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值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分。
输入
一行,两个数N、K
输出
两行,第一行升序输出设计的邮票面值,第二行输出“MAX=xx”(不含引号),其中xx为所求的能得到的连续邮资最大值。
样例输入
3 2
样例输出
1 3 MAX=7
思路:
假如现在已经得到选择了N张邮票,并且各种邮票价值之后为sum,那么我们可以用完全背包求出dp[j],即凑出j元至少需要的邮票数目。
首先要考虑到价值为1的邮票一定要选,因为只有选1,才能凑出1呀。然后我们进行搜索,有三个状态,现在已经选择的邮票数,最大符合题意的值,选择的邮票价值之和。
每次枚举从上一次枚举的邮票价值tmp[x]+1,到maxx+1,为什么不是maxx+2,因为在上一种状态maxx+1就凑不出,这次若选maxx+2,那么maxx+1就更凑不出来了。
每次搜索进行dp一次,求出现在的符合题意的值。
代码:
#include<iostream>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#include<string.h>
#include<queue>
#include<stack>
#include<cstdio>
#include<cmath>
#include <stdlib.h>
#include<stack>
using namespace std;
const int maxn=100000+10;
#define mod 1000000007
#define INF 0x3f3f3f3f
int dx[]= {-1,1,0,0};
int dy[]= {0,0,-1,1};
int n,k;
int dp[maxn];
int tmp[maxn];
int ans[maxn];
int dpp(int N,int sum)
{
memset(dp,333,sizeof(dp));
dp[0]=0;
rep(i,1,N)
{
rep(j,tmp[i],sum*n)
{
dp[j]=min(dp[j],dp[j-tmp[i]]+1);
}
}
rep(i,1,sum*n)
{
if(dp[i]>n)return i-1;
}
return sum*n;
}
int mans;
void dfs(int x,int maxx,int s)
{
if(x==k)
{
if(maxx>mans)
{
mans=maxx;
rep(i,1,k)
{
ans[i]=tmp[i];
}
}
return ;
}
rep(i,tmp[x]+1,maxx+1)
{
tmp[x+1]=i;
int ms=dpp(x+1,s+i);
dfs(x+1,ms,s+i);
}
return ;
}
int main()
{
cin>>n>>k;
mans=0;
tmp[1]=1;
dfs(1,n,1);
rep(i,1,k)
{
cout<<ans[i]<<" ";
}
cout<<endl;
cout<<"MAX="<<mans<<endl;
return 0;
}