信息学奥赛一本通 1941:【07NOIP普及组】Hanoi双塔问题 | 洛谷 P1096 [NOIP2007 普及组] Hanoi 双塔问题

这篇博客介绍了汉诺塔双塔问题的解题思路,包括递推和迭代两种方法,并针对高精度计算的需求提供了三种不同的实现方式:整型数组表示、结构体表示和高精度数字类。每种方法都从低精度转换为高精度,以处理大数值的计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目链接】

ybt 1941:【07NOIP普及组】Hanoi双塔问题
洛谷 P1096 [NOIP2007 普及组] Hanoi 双塔问题

【题目考点】

1. 递推/递归
2. 高精度

【解题思路】

该问题为汉诺塔问题的变种。可以用递推或递归的方法完成。

解法1:递推

  • 递推状态:记a[i]为将2*i个圆盘从A柱移动到C柱的圆盘移动次数。
  • 初始状态:a[1] = 2
  • 递推关系:要想将2*i个圆盘从A柱移动到C柱,需要先把2*(i-1)个圆盘从A柱移动到B柱,需要移动a[i-1]次。而后将剩下的2个圆盘从A柱移动到C柱,移动2次。最后把B柱的2*(i-1)个圆盘移动到C柱,需要移动a[i-1]次。所以a[i] = 2*a[i-1] + 2
    假设所有变量都是低精度数字,写出代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n, a[205];
    cin >> n;
    a[1] = 2;
    for(int i = 2; i <= n; ++i)
    	a[i] = 2 * a[i-1] + 2;
    cout << a[n];
    return 0;
}

观察递推公式,可知 a i > 2 a i − 1 > 2 2 a i − 2 > . . . > 2 i − 1 a 1 = 2 i a_i > 2a_{i-1} > 2^2a_{i-2}>...>2^{i-1}a_1=2^i ai>2ai1>22ai2>...>2i1a1=2i
题目中n最大为200,那么 a n > 2 n = 2 200 a_n>2^n=2^{200} an>2n=2200,求这个数字的位数: ⌊ l o g 10 2 200 ⌋ + 1 ≈ 62 \lfloor log_{10}2^{200}\rfloor +1\approx 62 log102200+162,这一定是个基本变量类型无法表示的数字,需要使用高精度数字。
观察低精度代码中,a应该从整型数组变为高精度数字的数组,2*a[i-1]+2中,乘法是高精乘低精的运算,加法是高精加低精的运算。也可以实现高精加高精运算,将整数2转为高精度数后再计算。
可以用整型数组表示高精度数字,也可以把整型数组放在结构体中,构建高精度数字类型。也可以构建高精度数字类。

解法2:迭代:

也可以把上述递推代码变递推为迭代,而后将该低精度代码变为高精度。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n, f;
    cin >> n;
    f = 2;
    for(int i = 2; i <= n; ++i)
    	f = 2 * f + 2;
    cout << f;
    return 0;
}

解法2:递归

低精代码为

#include <bits/stdc++.h>
using namespace std;
int solve(int i)
{
	if(i == 1)
		return 2;
	return 2 * solve(i - 1) + 2;
}
int main()
{
    int n;
    cin >> n;
    cout << solve(n);
    return 0;
}

把该代码改为高精度代码即可。

【题解代码】

解法1:递推
  • 写法1:整型数组表示高精度数字
#include<bits/stdc++.h>
using namespace std;
#define N 105
void setLen(int a[], int i)
{
	while(a[i] == 0 && i > 1)
		i--;
	a[0] = i;
} 
void Multiply(int a[], int b, int r[])//高精乘低精 r = a * b
{
    int c = 0, i;
    for(i = 1; i <= a[0]; ++i)
    {
        r[i] = a[i] * b + c;
        c = r[i] / 10;
        r[i] %= 10; 
    }
    while(c > 0)
    {
        r[i] = c % 10;
        c /= 10;
        i++;
    }
   	setLen(r, i);
}
void Add(int a[], int b)//高精加低精 a += b
{
    int c = b, i = 1;
    while(c > 0)
    {
    	a[i] += c;
    	c = a[i] / 10;
    	a[i] %= 10;
    	i++;
	}
	if(i > a[0])
    	setLen(a, i);
}
void showNum(int a[])
{
    for(int i = a[0]; i >= 1; --i)
        cout << a[i];
}
int main()
{
	int n, a[205][N] = {};//a[i]:2*i层汉诺塔从A移动到C的步数
	cin >> n;
	a[1][0] = 1, a[1][1] = 2;//a[1] = 2;
	for(int i = 2; i <= n; ++i)
	{
		Multiply(a[i-1], 2, a[i]);//a[i] = 2*a[i-1];
		Add(a[i], 2);//a[i] += 2
	}
	showNum(a[n]);
    return 0;
}

  • 写法2:高精度数类
#include<bits/stdc++.h>
using namespace std;
#define N 105
struct HPN
{
	int a[N] = {};
	HPN(){}
	HPN(string s)
	{
		a[0] = s.length();
		for(int i = 1; i <= a[0]; ++i)
			a[i] = s[a[0] - i] - '0';
	}
	HPN(int v)
	{
		do
		{
			a[++a[0]] = v%10;
			v /= 10;
		} while(v > 0);
	}
	int& operator [] (int i)
	{
		return a[i];
	}
	void setLen(int i)
	{
		while(i > 1 && a[i] == 0)
			i--;
		a[0] = i;
	} 
	HPN operator * (int b)//a *= b
	{
		HPN r; 
		int c = 0, i;
	    for(i = 1; i <= a[0]; ++i)
	    {
	        r[i] = a[i] * b + c;
	        c = r[i] / 10;
	        r[i] %= 10; 
	    }
	    while(c > 0)
	    {
	        r[i] = c % 10;
	        c /= 10;
	        i++;
	    }
	   	r.setLen(i);
	   	return r;
	}
	HPN operator + (HPN b)
	{
		HPN r;
		int i, c = 0;
		for(i = 1; i <= max(a[0], b[0]); ++i)
		{
			r[i] = a[i]+b[i]+c;
			c = r[i]/10;
			r[i] %= 10;
		}
		r[i] = c;
		r.setLen(i);
		return r;
	}
	void show()
	{
		for(int i = a[0]; i >= 1; --i)
			cout << a[i];
	}
} a[205];
int main()
{
	int n;
	cin >> n;
	a[1] = 2;
	for(int i = 2; i <= n; ++i)
		a[i] = a[i-1]*2+HPN(2);
	a[n].show();
    return 0;
}
解法2:迭代 结构体表示高精度数字
#include<bits/stdc++.h>
using namespace std;
#define N 105
struct HPN
{
	int a[N] = {};
};
void setLen(int a[], int i)
{
	while(a[i] == 0 && i > 1)
		i--;
	a[0] = i;
} 
void Multiply(HPN &a, int b)//高精乘低精 a *= b
{
    int c = 0, i;
    for(i = 1; i <= a.a[0]; ++i)
    {
        a.a[i] = a.a[i] * b + c;
        c = a.a[i] / 10;
        a.a[i] %= 10; 
    }
    while(c > 0)
    {
        a.a[i] = c % 10;
        c /= 10;
        i++;
    }
   	setLen(a.a, i);
}
void Add(HPN &a, int b)//高精加低精 a += b
{
    int c = b, i = 1;
    while(c > 0)
    {
    	a.a[i] += c;
    	c = a.a[i] / 10;
    	a.a[i] %= 10;
    	i++;
	}
	if(i > a.a[0])
    	setLen(a.a, i);
}
void showNum(HPN a)
{
    for(int i = a.a[0]; i >= 1; --i)
        cout << a.a[i];
}
int main()
{
	int n;
	cin >> n;
	HPN f;
	f.a[0] = 1, f.a[1] = 2;//f = 2;
	for(int i = 2; i <= n; ++i)
	{
		Multiply(f, 2);//f *= 2
		Add(f, 2);//f += 2
	}
	showNum(f);
    return 0;
}
解法3:递归 高精度数字类
#include<bits/stdc++.h>
using namespace std;
#define N 105
struct HPN
{
	int a[N] = {};
	HPN(){}
	HPN(string s)
	{
		a[0] = s.length();
		for(int i = 1; i <= a[0]; ++i)
			a[i] = s[a[0] - i] - '0';
	}
	int& operator [] (int i)
	{
		return a[i];
	}
	void setLen(int i)
	{
		while(i > 1 && a[i] == 0)
			i--;
		a[0] = i;
	} 
	HPN operator * (int b)//a *= b
	{
		HPN r; 
		int c = 0, i;
	    for(i = 1; i <= a[0]; ++i)
	    {
	        r[i] = a[i] * b + c;
	        c = r[i] / 10;
	        r[i] %= 10; 
	    }
	    while(c > 0)
	    {
	        r[i] = c % 10;
	        c /= 10;
	        i++;
	    }
	   	r.setLen(i);
	   	return r;
	}
	HPN operator + (int b)
	{
		HPN r = *this;
		int c = b, i = 1;
	    while(c > 0)
	    {
	    	r[i] += c;
	    	c = r[i] / 10;
	    	r[i] %= 10;
	    	i++;
		}
		if(i > r[0])
	    	r.setLen(i);
	    return r;
	}
	void show()
	{
		for(int i = a[0]; i >= 1; --i)
			cout << a[i];
	}
};
HPN solve(int i)
{
	if(i == 1)
		return HPN("2");
	return solve(i - 1) * 2 + 2;//高精乘低精 高精加低精 
}
int main()
{
	int n;
	cin >> n;
	HPN r = solve(n);
	r.show();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值