[洛谷P1021][题解]邮票面值设计

我才不是题目呢~

0.序

偶然被老师强迫刷到了这样一道题,正好亿年没写题解了,来此练练手+摸鱼

1.概述

基本思路:DFS暴力枚举+DP验证。
先DFS出来一个序列,然后DP出所有面值用到的最少邮票数。
(f[i])为凑出(i)面值用到的最少邮票张数。
方程是我们在幼儿园就接触过的(f[i]=min(f[i],f[i-a[j]]+1))
(a)数组为临时面值数组。
求出f数组之后就枚举到第一个大于n的就行了。
设计一下DFS:
void DFS(int dep,int now,int tmp)
dep:当前枚举了多少数;
now:当前数;
tmp:上一个最大面值。
然后就没了。

2.细节

for(rg int i=now+1;i<=tmp+1;i++){
	a[dep]=i;
	DFS(dep+1,i,DP(dep));	
}

下界的now+1不用说,关键是上界。
i肯定是尽量往大里枚举,
但如果枚举到tmp+2的话中间就会空出一个数,不符合题目要求。
所以此处为tmp+1。(不多不少刚刚好)
2.
题目中没有给出最大面值为多少,所以f数组看着开吧。

3.代码

省去了又臭又长的缺省源。

int n,k,a[50],f[100010],ans[50],maxs;
inline int DP(int x){
	memset(f,0x3f,sizeof(f));
	f[0]=0;
	for(rg int j=1;j<=x;j++){
		for(rg int i=a[j];i<=a[x]*n;i++){
			f[i]=min(f[i],f[i-a[j]]+1);
		}
	}
	for(rg int i=1;i<=a[x]*n;i++){
		if(f[i+1]>n)return i;
	}
	return a[x]*n;
}
void DFS(int dep,int now,int tmp){
	if(dep>k){
		if(tmp>maxs){
			maxs=tmp;
			for(rg int i=1;i<=k;i++){
				ans[i]=a[i];
			}
		}
		return;
	}
	for(rg int i=now+1;i<=tmp+1;i++){
		a[dep]=i;
		DFS(dep+1,i,DP(dep));	
	}
}
int main(){
	Read(n),Read(k);
	DFS(1,0,0);
	for(rg int i=1;i<=k;i++){
		cout<<ans[i]<<" ";
	}
	cout<<endl;
	cout<<"MAX="<<maxs<<endl;
	return 0;
}

4.完结撒花

原文地址:https://www.cnblogs.com/juruoajh/p/13144610.html