P1021 邮票面值设计(dfs+背包dp)
P1021 邮票面值设计
题意:
给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤15N+K≤15)种邮票的情况下
(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,
使在1至MAX之间的每一个邮资值都能得到。
思路:
dfs+背包dp
暴搜k种邮票,下一种邮票的取值就是上一张邮票值+1,到上一次选的最大值+1;
比如这上一次你选了1,n=3时,下一次你能选的就是2,3,4;
然后怎么确定当前选择i之后的最大值呢,就是用到背包dp,dp[i]表示凑
到i时所用的最少邮票数。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define N 105 int n,k; int res; int ans[N],tmp[N],dp[2005]; int get(int cur,int sum) { memset(dp,0x3f3f3f3f,sizeof(dp)); dp[0]=0; for(int i=1;i<=cur;i++) { for(int j=tmp[i];j<=n*sum;j++) dp[j]=min(dp[j],dp[j-tmp[i]]+1);; } for(int i=1;i<=n*sum;i++) if(dp[i]>n) return i-1; return n*sum; } void dfs(int cur,int L1,int L2,int sum) { if(cur>k) { if(res<L2) { res=L2; for(int i=1;i<=n;i++) ans[i]=tmp[i]; } return ; } for(int i=L1+1;i<=L2+1;i++) { tmp[cur]=i; int x=get(cur,sum+i); dfs(cur+1,i,x,sum+i); } } int main() { while(~scanf("%d %d",&n,&k)) { res=0; dfs(1,0,0,0); for(int i=1;i<=k;i++) printf("%d ",ans[i]); printf("\nMAX="); printf("%d\n",res); } return 0; }