题意:
给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1至MAX之间的每一个邮资值都能得到。
思路:
没思路。。。强行搜索。先枚举邮票组合,再求组合对应的MAX。
后一张邮票面值的枚举范围是(前一张面值+1——目前最长可取到的MAX+1)
MAX用多重背包求解(未二进制优化,N较小影响不大)。
关于搜索复杂度的计算:
据说指数级的复杂度没有必要算,只要把该剪的枝剪了,应该就能过。
PS:
这道题一开始没过,因为数组开太大,最后一个点TLE。
其实也不大,最于7 8这种数据可能还嫌太小,但经测试,1000就可以过了。
(试了一下7 8,不知道何年何月能给出结果。。。)
#include<iostream> #include<vector> #include<queue> #include<cstring> #include<algorithm> #include<cmath> #include<cstdio> #include<map> #define INF 0x7f7f7f7f #define MAX_INT 0x7fffffff #define pi 3.1415926 typedef unsigned int uint; using namespace std; typedef long long LL; int ci[1000],n,k,maxc=0,contin,value[15];
//value[]=记录邮票面值
//contin=单个组合的MAX
//maxc=所有组合的MAX,即所求
//ci[i]=构成i价值所需的最少邮票数
//maxc=连续的邮资最大值 int dfs(int dpsj,int v,int c){//dpsj最大可达到的价值 = maxv*N int beifen[1000],p; for(int i=dpsj;i>=0;i--){ if(ci[i]>n)continue; for(int j=n-ci[i];j;j--){ p=i+j*v; ci[p]=min(ci[p],ci[i]+j); } } for(int i=0;i<1000;i++)beifen[i]=ci[i]; while(ci[contin+1]<=n)contin++; if(c==k) if(contin>maxc){ maxc=contin; value[c]=v; return 1; } else{ return 0; } int sj=contin+1,f=0; for(int i=v+1;i<=sj;i++){ if(dfs(v*n,i,c+1)){ value[c]=v; f=1; } for(int i=0;i<1000;i++)ci[i]=beifen[i]; contin=sj-1; } return f; } int main(){ memset(ci,1,sizeof(ci)); ci[0]=0; cin>>n>>k; contin=n; dfs(0,1,1); for(int i=1;i<=k;i++)cout<<value[i]<<' '; cout<<endl; cout<<"MAX="<<maxc<<endl; return 0; }