码题集 硬币塔

以下是题目:

 首先为表示方便,以左代下,以右代上,对此题进行分析: 

在此先假设 GetGold( n,i)表示:n级硬币塔从下往上数i步所经过的金币数

题中给出的k层硬币塔的结构是这样的:

 银币        k-1级硬币塔     k个金币   k-1级硬币塔   银币

我们可以类似的将该结构看成一个数轴,第一个银币左边的位置为原点。

为表示端点的值,我们假设floor(n) 表示n级硬币塔的层数

 而题目想给出i步,计算从下往上有几个金币,对此,显然有以下7种情况:

①i<=0时,显然  GetGold( n,i)为0;

②i=1时,   如果n=0,则GetGold (n,i)为1,若n>=1,则GetGold(n,i)为0;

③1<i<=1+floor(n-1)时,GetGold(n,i) 就相当于减去最左边的银币后,对n-1级硬币塔进行i-1步检索,也就有  GetGold(n,i) = GetGold(n-1,i-1);

④1+floor(n-1)<i<=1+floor(n-1)+k时,此时经过的金币数为n-1级硬币塔的金币数加上(k-i)个金币,即

                        GetGold(n,i) =  GetGold(n-1,floor(n-1) ) +(k-i);

⑤1+floor(n-1)+k<=i <= 1+2*floor(n-1)+k时,此时情况 其实是③④的结合,此时经过的金币数为n-1级硬币塔的金币数加上k个金币,对n-1级硬币塔进行i-1-floor(n-1)-k步检索,也就有

                GetGold(n,i) =  GetGold(n-1,floor(n-1))+k+GetGold( n-1,i-1-floor(n-1)-k);

⑥i=1+2*floor(n-1)+k+1时,此时相当于在⑤后多数了一步,并且最后数的硬币刚刚好是最后一个银币,即有GetGold(n,i) =  GetGold(n-1,floor(n-1))+k+GetGold( n-1,i-1-floor(n-1)-k-1);

⑦i>1+2*floor(n-1)+k+2 时,由题可得,floor(n) = 1+2*floor(n-1)+k+2,故此时有

i>floor(n),因此 GetGold(n,i) = GetGold(n, floor(n) )。

对以上的情况进行简要综合分析,

I.当 i<0时,GetGold(n,i) = 0;

II.当i> =floor(n) 时, GetGold(n,i) = GetGold(n,floor(n) );

根据上述两种情况,当0<i < floor(n) 时,

GetGold(n,i) =  GetGold(n-1,  i-1) + (i-floor[n-1]-1)<=0 ? 0:(i-floor[n-1]-1)>=n?n:(i-floor[n-1]-1) + GetGold(n-1,i-floor[n-1]-1-n )

在此我们对此进行上述该式子进行分析:

GetGold(n-1,  i-1) 这一项表示,第一个n-1级硬币塔的走i-1步的金币数,显然i-1<floor(n) 时能正常表示,i-1>=floor(n)时,可由II式子转化成GetGold(n,floor(n) );

(i-floor[n-1]-1)<=0 ? 0:(i-floor[n-1]-1)>=n?n:(i-floor[n-1]-1)这一项表示,当i<=floor[n-1]+1即为情况③时,经过的中间层(k个金币层)只有0个金币;而当i>=n+floor[n-1]+1即为情况⑤时,经过的中间层有k个金币;当floor[n-1]+1<i<n+floor[n-1]+1即为情况④时,经过的中间层有(i-floor[n-1]-1)个金币。

GetGold(n-1,i-floor[n-1]-1-n)这一项表示,第二个n-1级硬币塔,在走完前面 一个银币,一个n-1级硬币塔,k个金币后,还需走的i-floor[n-1]-1-n步在n-1级硬币塔中经过的金币数,

当i-floor[n-1]-1-n>floor[n-1]时,由Ⅱ可转变成GetGold(n-1,floor(n-1));

当i-floor[n-1]-1-n<=floor[n-1]时,由Ⅰ将直接返回0;

综上所述,我们需要先根据递归公式,floor[n] = 2*Getfloor(n-1)+2+n,推出n级硬币塔的层数;

接着对GetGold(n,i)设计分段函数:

当n=0时,若i>0,则GetGold(n,i) = 1;反之,GetGold(n,i) = 0;

当 i<=0时,GetGold(n,i) = 0;

当0<i<floor(n)时,GetGold(n,i) =  GetGold(n-1,  i-1) + (i-floor[n-1]-1)<=0 ? 0:(i-floor[n-1]-1)>=n?n:(i-floor[n-1]-1) + GetGold(n-1,i-floor[n-1]-1-n )

当i> =floor(n) 时, GetGold(n,i) = GetGold(n,floor(n) );

为避免重复调用函数,我们可以通过哈希表记录已经得出结果的GetGold(n,i)的值,以期望下次需要求得GetGold(n,i)的值时不必继续递归,直接返回结果。

那么以下便是代码:

#include<iostream>
#include <vector>
#include <map>

using namespace std;
map < pair< long long, long long> , long long> mp;
vector< long long> floor;
 long long Getfloor(  long long n){
 	//初值条件 
	if( n == 0) {
		floor[n] = 1;
		return floor[n];
	}
	//递推公式 
	floor[n] = 2*Getfloor(n-1)+2+n;
	return floor[n]; 
}

 long long GetGold(  long long n, long long i){
	if( i<=0) return 0;
	if(n==0) return 1;
	if( mp.count( {n,i}) ) return mp[ {n,i}];
	if( i>floor[n]) return GetGold(n,floor[n]);
	mp[{n,i}] =  GetGold(n-1,min(floor[n-1],i-1))+GetGold(n-1,max(i-floor[n-1]-1-n,(long long)0));
	mp[{n,i}] += (i-floor[n-1]-1)<=0 ? 0:(i-floor[n-1]-1)>=n?n:(i-floor[n-1]-1);
	return mp[ {n,i}];
}
int main( )
{
    long long n,i;
	cin>>n>>i;
	floor.resize(n+1);
	Getfloor(n);
	cout<<GetGold(n,i)<<endl;
	floor.clear();
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值