洛谷P1021邮票面值设计题解--zhengjun
题目描述
给定一个信封,最多只允许粘贴\(N\)张邮票,计算在给定\(K\)(\(N+K\leq 15\))种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值\(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\)分。
输入格式
\(2\)个整数,代表\(N\),\(K\)。
输出格式
\(2\)行。第一行若干个数字,表示选择的面值,从小到大排序。
第二行,输出“\(MAX=S\)”,\(S\)表示最大的面值。
输入输出样例
输入 #1 复制
3 2
输出 #1 复制
1 3
MAX=7
思路
动态规划,用\(f_{i}\)表示拼成\(i\)最少需要多少张邮票。
转移公式:\(f_j=min(f_j,f_{j-a_i}+1)\)
再来一个\(dfs\)就可以了。
(加上一个回溯)
代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[21];
int maxx=0,ans[21];
int f[51000];
int dp(int k){
memset(f,63,sizeof(f));//附一个较大的值
f[0]=0;
for(int i=1;i<=k;i++)
for(int j=a[i];j<=a[k]*n;j++)
if(f[j-a[i]]<n)
f[j]=min(f[j],f[j-a[i]]+1);
int x=0;
while(f[x+1]<=100)
x++;
return x;
}
void dfs(int k){
if(k==m+1){
int t=dp(k-1);
if(t>maxx){
maxx=t;
memcpy(ans,a,sizeof(ans));
}
return;
}
int end=dp(k-1);
for(int j=a[k-1]+1;j<=end+1;j++){
a[k]=j;
dfs(k+1);
a[k]=0;
}
}
int main(){
cin>>n>>m;
a[1]=1;
dfs(2);
for(int i=1;i<=m;i++)
printf("%d ",ans[i]);
printf("\nMAX=%d\n",maxx);
return 0;
}