洛谷P1021邮票面值设计题解--zhengjun

题目描述

给定一个信封,最多只允许粘贴 N N 张邮票,计算在给定 K K N + K 15 N+K\leq 15 )种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值 M A X MAX ,使在 1 1 M A X MAX 之间的每一个邮资值都能得到。

例如, N = 3 N=3 K = 2 K=2 ,如果面值分别为 1 1 分、 4 4 分,则在 1 1 分~ 6 6 分之间的每一个邮资值都能得到(当然还有 8 8 分、 9 9 分和 12 12 分);如果面值分别为 1 1 分、 3 3 分,则在 1 1 分~ 7 7 分之间的每一个邮资值都能得到。可以验证当 N = 3 N=3 K = 2 K=2 时, 7 7 分就是可以得到的连续的邮资最大值,所以 M A X = 7 MAX=7 ,面值分别为 1 1 分、 3 3 分。

输入格式

2 2 个整数,代表 N N K K

输出格式

2 2 行。第一行若干个数字,表示选择的面值,从小到大排序。

第二行,输出“ M A X = S MAX=S ”, S S 表示最大的面值。

输入输出样例

输入 #1 复制
3 2
输出 #1 复制
1 3
MAX=7

思路

动态规划,用 f i f_{i} 表示拼成 i i 最少需要多少张邮票。
转移公式: f j = m i n ( f j , f j a i + 1 ) f_j=min(f_j,f_{j-a_i}+1)
再来一个 d f s 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

发布了48 篇原创文章 · 获赞 49 · 访问量 2148

猜你喜欢

转载自blog.csdn.net/A_zjzj/article/details/104500360