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

谢谢--zhengjun

posted @ 2022-06-10 18:43  A_zjzj  阅读(71)  评论(0编辑  收藏  举报