• 洛谷 P1021 邮票面值设计


    原题链接:[NOIP1999 提高组] 邮票面值设计 - 洛谷

    目录

    题目描述

    解题思路:

    代码实现:

    题后总结:


    题目描述

    给定一个信封,最多只允许粘贴 N 张邮票,计算在给定 K(N+K≤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, 表示最大的面值。

    输入输出样例

    输入 #1

    3 2
    

    输出 #1

    1 3
    MAX=7

    解题思路:

    此题主要利用了dp+dfs,根据题目来看需要k种邮票,那么需要哪几种邮票,这就需要枚举,dfs去每一步搜索,题目中要求最大连续长度,考虑dp去解决,要求最大连续长度,意思就是通过这k种面值,能够连续不间断组成1~?之间的每一个数,那么我定义一个f[M]表示通过k种面值得到分值为M的最少邮票张数,只要这个值小于题目中给定的邮票张数n,那么从小到达遍历,此位置前面的都是连续的,当找到第一个不满足

    那么我们重新顺一下解题思路,首先枚举这k种邮票面值组合,我们解决办法是最简单的dfs,我们枚举出这k种面值组合,对它进行求解最大连续长度,处理办法是dp,具体解释注释在代码上。


    代码实现:

    1. #include
    2. #include
    3. using namespace std;
    4. const int N=20;
    5. const int inf=0x3f3f3f;
    6. int n,k,res;//res保存答案
    7. int a[N],ans[N],f[50000];//f[i]拼面值为i所需要最小张数
    8. //a[i]组成的分数中间过渡数组,ans[i]满足条件的答案分数数组
    9. int dp(int t,int mx){
    10. f[0]=0;//初始化特例
    11. for(int i=1;i<=a[t]*n;i++)f[i]=inf;//初始化正无穷
    12. for(int i=1;i<=k;i++){//k种位数
    13. for(int j=a[i];j<=a[t]*n;j++){//最大连续长度至少以自己分数为起始,最大到填满n张最大的面值a[t]
    14. f[j]=min(f[j],f[j-a[i]]+1); //类似于背包更新
    15. }
    16. }
    17. for(int i=1;i<=a[t]*n;i++){
    18. if(f[i]>n){//若此时填的面值张数大于邮票可以贴的最大张数,就说明此时i不满足,前i-1是满足的
    19. return i-1;
    20. }
    21. }
    22. return a[t]*n;//若前面都成立那么最大连续分数就是最大值分数*张数
    23. }
    24. void dfs(int dep,int x){//dep种分数组成x为连续最大长度
    25. if(dep==k+1){//当分数种数为k种,满足条件
    26. if(x>res){//此时最大连续长度大于res满足更新条件
    27. res=x;//更新
    28. for(int i=1;i<=k;i++){
    29. ans[i]=a[i];
    30. }
    31. }
    32. return;
    33. }
    34. for(int i=a[dep-1]+1;i<=x+1;i++){//为了不避免重复,至少是上一位的分数值+1,最大到x+1,否则前面的也会不连续
    35. a[dep]=i;
    36. int t=dp(dep,x);//t更新最大连续长度
    37. dfs(dep+1,t);
    38. }
    39. }
    40. int main(){
    41. cin>>n>>k;
    42. dfs(1,0);//从1开始去找,第一个分必是1,初始最大长度为0
    43. for(int i=1;i<=k;i++)
    44. cout<" ";
    45. cout<
    46. cout<<"MAX="<
    47. return 0;
    48. }

    题后总结:

    此题博主感觉难度较大,如果题量够大,可能对他们来说,一眼就出思路,dfs+dp这种题第一次做,当时看的是罗老师的B站讲解,大家看不懂的可以去看看。

    信奥编程罗老师:P1021 [NOIP1999 提高组] 邮票面值设计_哔哩哔哩_bilibili

    :图片来自罗老师讲解。

  • 相关阅读:
    微擎模块 啦啦外卖跑腿小程序最新版14.3 带最新跑腿前端+教学视频 完整包
    虚拟机服务器中了lockbit3.0勒索病毒怎么办,lockbit3.0勒索病毒解密数据恢复
    浙大恩特客户资源管理系统任意文件上传漏洞复现
    003 PythonTCP网络通信
    放大器的稳定性分析举例
    工作之余想线上学习软件测试靠谱么?
    基于WOA的VMD超参数优化
    基于B/S机场飞机票网上订票管理系统【Java毕业设计·安装调试·代码讲解·文档报告】
    RHEL 8.6 NFS 服务端安装配置
    NXP公司K60N512+PWM控制BLDC电机
  • 原文地址:https://blog.csdn.net/m0_73633807/article/details/138170284