CJOJ P2221 -【中学高重点内容级本】邮票
本人第一次写博客,有问题请多多海涵
Description
邮局发行一套票面有n(0<n<=10)种不同面值的邮票。若限每封信所贴的邮票张数不得超过m枚,存在整数r使得用不超过m(0<m<=2n)枚的邮票,可以贴出连续整数1,2,3,…,r值来,找出这种面值数,使得r值最大。
Input
一行,输入N及M
Output
输出R
Sample Input
2 3
Sample Output
7
Solution
按照题目的意思,由于要找出最大能拼出的数,因此要用一个函数dp(),来找出最大能拼出的数,然而要找出这个数,还需要找出这n种邮票分别为多少,所以还需要一个函数dfs(),这个函数用来找这n种邮票。
此时,我们可以用一个数组a[x],来储存第x种邮票的面值为多少,同时,用一个数组f[i]表示要凑出总值为i的最少需要的邮票数,a[x]用于找下一个邮票面值,f[i]用于找当前情况下最大能组成的数值,即max(r)。
详细代码(附带每一步的解释)如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,a[100],maxr,f[10000];
void init()
{
cin>>n>>m;
a[1]=1;
}
int DP(int n)
{
int i,j;
f[0]=0;
for(i=1;;i++)//枚举总值
{
f[i]=-1;//f[i]存要凑出总值为i的最少需要的邮票数
for(j=1;j<=n;j++)//枚举邮票面值a[j]
if(i-a[j]>=0/*a[j]可以用来凑i*/ && f[i-a[j]]+1<=m/*加上后邮票数不超过m*/ &&(f[i]==-1 || f[i-a[j]]+1<=f[i])/*可以更新f[i]的值*/)
f[i]=f[i-a[j]]+1;//更新f[i]的值
if(f[i]==-1)//凑不出来
return i-1;//
}
}
void DFS(int p)
{
if(p>n)//如果面值大于i,那么就不能再往下dfs,已经到了更新答案的时候了
{
int s=DP(n);//n种邮票面值可以凑出的最大值
if(s>maxr)
{
maxr=s;
}
return;
}
int i;//如果还可以往下深搜
for(i=a[p-1]+1;i<=DP(p-1)+1;i++)//枚举可以新放的邮票的值,从a[p-1]->目前最大邮票单张面额,dp(p-1)+1->下一张最大单张邮票面额,也就是枚举a[p]可以有的值
{
a[p]=i;//更新此时a[p]的值
DFS(p+1);//对此时已有邮票的单张面额进行深搜,更新a[p+1]的值,或者更新maxr
}
}
int main()
{
init();
DFS(2);
cout<<maxr<<endl;
}