题目描述
给定一个信封,最多只允许粘贴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”,S表示最大的面值。
输入输出样例
输入样例#1:
3 2
输出样例#1:
1 3 MAX=7
1 #include <iostream> 2 #include <string> 3 #include <cstdio> 4 #include <algorithm> 5 #include <stdlib.h> 6 7 using namespace std; 8 const int maxn=20; 9 int n,k;//张数 面值数 10 int maxx=0,kind[maxn],res[maxn]; 11 12 int dp(int t){ 13 //初始化f[] 14 int f[5000]={0};//达到连续到某数时需要的最小张数 15 for(int i=1;i<=kind[t]*n;i++) 16 f[i]=9999; 17 for(int i=1;i<=t;i++) 18 for(int j=kind[i];j<=kind[t]*n;j++){ 19 f[j]=min(f[j],f[j-kind[i]]+1); 20 } 21 for(int i=1;i<=kind[t]*n;i++){ 22 if(f[i]>n) 23 return i-1; 24 } 25 return kind[t]*n; 26 } 27 28 void dfs(int t,int maxnum){//第几张面值 目前可以连续到多少 29 if(t==k+1) 30 { 31 if(maxnum>maxx) 32 { 33 maxx=maxnum; 34 for(int i=1;i<=k;i++) 35 res[i]=kind[i]; 36 } 37 return; 38 } 39 for(int i=kind[t-1]+1;i<=maxnum+1;i++) 40 { 41 kind[t]=i; 42 int _maxnum=dp(t); 43 dfs(t+1,_maxnum); 44 } 45 } 46 47 int main() 48 { 49 scanf("%d%d",&n,&k); 50 dfs(1,0); 51 printf("%d",res[1]); 52 for(int i=2;i<=k;i++) 53 printf(" %d",res[i]); 54 printf("\nMAX=%d\n",maxx); 55 return 0; 56 }
dp+dfs
解释: dfs(t,maxnum) 表示搜索到了第 t 张面值选择,而前 t+1 张能够最多连续取值 1~maxnum
dp(t) 返回在某次搜索中,此时 t 张面值能够最多连续取值的最大值
面值是递增存放的
思路:
dp:状态转移: f[x]=min(f[x],f[x-kind[i]]+1) 其中f数组中存储的是在这次搜索中,t张面值的纸币来取到x最小需要几张
在每次一点点将每张面值加进去的时候(即17行dp函数外层循环),由于x(在这张面值加入进去能够取到的数)最小为这张面值,最大为 kind[t]*n (即最大面值有最大张数时),所以内层循环的边界是这样写的
dfs比较清楚
最近不是很想干正事~昨天不然应该写完的,但是后来还是打了一晚上游戏(*?ω-q)
所以虽然难度标的是普及,但当时根本没心思写所以感觉超难……
原文地址:https://www.cnblogs.com/yalphait/p/8761824.html
时间: 2024-10-16 09:24:30