描述
給定一個信封,最多隻允許粘貼N張郵票,計算在給定M(N+M<=10)種郵票的情況下(假定所有的郵票數量都足夠),如何設計郵票的面值,能得到最大max ,使得1~max之間的每一個郵資值都能得到。
例如,N=3,M=2,如果面值分別爲1分、4分,則在l分~6分之間的每一個郵資值都能得到(當然還有8分、9分和12分):如果面值分別爲1分、3分,則在1分~7分之間的每一個郵資值都能得到。可以驗證當N=3,M=2時,7分就是可以得到連續的郵資最大值,所以MAX=7,面值分別爲l分、3分。
樣例輸入:共一行,兩個整數,分表爲N與M的值。
格式
輸入格式
一行,分別爲N,M。
輸出格式
兩行。
第一行爲m種郵票的面值,按升序排列,各數之間用一個空格隔開。
第二行爲最大值。
如果有多解,輸出字典序最大的一個。
限制
各個測試點1s
來源
NOIP1999
思路
代碼
#include <iostream>
using namespace std;
int dp[1010],n,m,arr[11],cnt,ans[11];
int cal(int num) //計算num種郵票所能形成的最大連續面額
{
if(!num)return 0;
for(int i=0;i<1010;i++)
dp[i]=100000; //賦初值勤
dp[0]=0;
int x=0;
while(dp[x]<=n) //如果郵資x的最少郵票數不超過n枚
{
for(int i=1;i<=num;i++)
dp[x+arr[i]]=min(dp[x+arr[i]],dp[x]+1);//利用動規揹包求每一種郵資所需的郵票數
x++;
}
return x-1;
}
inline void dfs(int x) //深搜第x種面額
{
int now=cal(x-1); //計算前x-1種郵票成形成的最大連續面額
if(x<=m) //如果還沒到第m種
for(int i=now+1;i>=arr[x-1];i--) //在a[i]*n+1~a[i]+1中找下一個面額
{
arr[x]=i; //第x種面額爲i
dfs(x+1); //深搜第x+1種面額
}
else
if(now>cnt) //如果超過了最大連續值
{
cnt=now; //更新最大連續值
for(int i=1;i<=m;i++) //保存各面額
ans[i]=arr[i];
}
}
int main()
{
cin>>n>>m; //最多n張郵票,m種
dfs(1); //深搜第一種面額
for(int i=1;i<m;i++) //輸出前m-1種面額
cout<<ans[i]<<' ';
cout<<ans[m]<<endl; //輸出最後一種面額
cout<<"MAX="<<cnt; //輸出最大值
return 0;
}