刷题记录:牛客[NOIP2007]Hanoi双塔问题

传送门:牛客

给定A、B、C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形)。现要将这些圆盘移到C柱上,在移动过程中可放在B柱上暂存。要求:
(1)每次只能移动一个圆盘;
(2)A、B、C三根细柱上的圆盘都要保持上小下大的顺序;
任务:设An为2n个圆盘完成上述任务所需的最少移动次数,对于输入的n,输出An。
输入:
1
输出:
2

关于汉诺塔问题,在这里有详细的介绍和代码解释,如果对汉诺塔问题的递推关系不清楚的话可以跳转观看后继续

然后我们看向这道题,运用基本汉诺塔问题的思想去看这道题,你会发现只要将每次的移动都重复一遍即可,我们就得到了这样一个式子f(n)=2*(2^n-1),但是作为当年普及组的最后一题显然不能是这么简单的,这道题的n达到了200,而之前我们的普通汉诺塔才26,所以我们就需要采用高精度的方法了,这里也不难,只要不断乘2即可

如果高精度不会请看向这里

下面为了实现方便,将直接计算2^(n+1)-2

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
int ans[30000];
int main() {
	int n;
	n=read();
	ans[1]=2;int lens=1;
	for(int i=2;i<=n+1;i++) {
		int jw=0;
		//高精度乘2部分
		for(int j=1;j<=lens;j++) {
			ans[j]=ans[j]*2+jw;
			jw=ans[j]/10;
			ans[j]%=10;
		}
		if(jw!=0) {
			lens++;
			ans[lens]+=jw;
		}
	}
	//因为后面需要减2,可能会涉及到补位的问题
	int pos=1;
	while(ans[pos]<2) {
		pos++;
	}
	//pos!=1表示该位就可以直接减掉2,不需要前面的退位
	if(pos!=1) {
		lens--;
		ans[pos]--;
		int ppos=pos-1;
		for(int j=ppos;j>=2;j--) ans[ppos]=9;
		ans[1]=ans[1]+10-2;
		for(int i=lens;i>=1;i--) cout<<ans[i];
	}else {
		ans[pos]-=2;
		for(int i=lens;i>=1;i--) cout<<ans[i];
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值