洛谷1021 邮票面值设计
本题地址: http://www.luogu.org/problem/show?pid=1021
题目描述
给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值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
————————————————————————————————————————————————
分析:连续邮资问题,这题数据范围有点怪。。最坏情况显然过不了但还是AC了。人家总结的很好了。By D_Double
我用搜索+剪枝写法,搜索出now[1..k],表示取这k种面值时能得到最大连续邮资,第i种面值搜索范围最小now[i-1]+1,最大是update(最大连续邮资)+1。
update函数更新用now[1..i]的面值取n个时能得到的最大连续邮资,只要搜索出所有组合就可以了。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXN 50
int n,k,kind,ans[MAXN],now[MAXN],max,x,maxans=0;
_Bool vis[1000];
void dfs_N(int num,int sum,int prev)
{
vis[sum]=1;
if(num==n+1)return;//选完n个邮票
int i;
for(i=prev;i<=kind;i++)//下一个邮票
{
dfs_N(num+1,sum+now[i],i);
}
}
int update(int x)//得到当前邮票种类集合的最大连续值
{
memset(vis,0,sizeof(vis));
dfs_N(1,0,1);
int i;for(i=1;vis[i+1];i++);
return i;
}
void dfs_K(int step,int best)//搜索面值种类方案
{
if(step==k+1)//选完k种面值
{
if(best>maxans)
{
maxans=best;
memcpy(ans,now,sizeof(now));
}
return;
}
int i;
for(i=now[step-1]+1;i<=best+1;i++)//下一种面值
{
now[step]=i;
kind=step;
dfs_K(step+1,update(best));
}
}
int main(void)
{
scanf("%d%d",&n,&k);
now[1]=1;max=n;
dfs_K(2,max);
int i;
for(i=1;i<=k;i++)printf("%d ",ans[i]);
printf("\nMAX=%d",maxans);
return 0;
}