ybt 1941:【07NOIP普及组】Hanoi双塔问题
洛谷 P1096 [NOIP2007 普及组] Hanoi 双塔问题
该问题为汉诺塔问题的变种。可以用递推或递归的方法完成。
a[i]
为将2*i个圆盘从A柱移动到C柱的圆盘移动次数。a[1] = 2
。a[i-1]
次。而后将剩下的2个圆盘从A柱移动到C柱,移动2次。最后把B柱的2*(i-1)个圆盘移动到C柱,需要移动a[i-1]
次。所以a[i] = 2*a[i-1] + 2
#include
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>2ai−1>22ai−2>...>2i−1a1=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⌋+1≈62,这一定是个基本变量类型无法表示的数字,需要使用高精度数字。
观察低精度代码中,a应该从整型数组变为高精度数字的数组,2*a[i-1]+2
中,乘法是高精乘低精的运算,加法是高精加低精的运算。
可以用整型数组表示高精度数字,也可以把整型数组放在结构体中,构建高精度数字类型。也可以构建高精度数字类。
也可以把上述递推代码变递推为迭代,而后将该低精度代码变为高精度。
#include
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;
}
低精代码为
#include
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;
}
把该代码改为高精度代码即可。
#include
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;
}
#include
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;
}
#include
using namespace std;
#define N 105
struct HPN
{
int a[N];
HPN()
{
memset(a, 0, sizeof(a));
}
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(a[i] == 0 && i > 1)
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;
}