每周一算__经典篇(一)

来源:互联网 发布:mysql大数据优化 编辑:程序博客网 时间:2024/06/05 15:49

  为了保持思维的活跃度,除了每天上班之外,利用闲暇时间每周做一道算法题,文章内容将包括解的思路并附带我自己的代码。另外,也是为了督促自己不断学习和进步,故开辟这么一个系列的文章,希望自己能够坚持下来。加油。。。。。

  注:下面的内容仅代表我自己个人在解决问题时候的想法以及我自己的解法,仅供参考,如果大家觉得我的思路和想法有什么可以改进或者错误的地方,欢迎指正,使用语言C/C++。


  好了,现在开始正文,作为系列的第一篇我选择的是经典算法中的河内塔(汉诺塔)问题,问题描述如下:

     河内之塔  说明河内之塔(Towers of Hanoi)是法国人M.Claus(Lucas)于1883年从泰国带至法国的,河内为越 战时北越的首都,即现在的胡志明市;1883年法国数学家 Edouard Lucas曾提及这个故事,据说创世纪时Benares有一座波罗教塔,是由三支钻石棒(Pag)所支撑,开始时神在第一根棒上放置64个由上至下依由小至大排列的金盘(Disc),并命令僧侣将所有的金盘从第一根石棒移至第三根石棒,且搬运过程中遵守大盘子在小盘子之下的原则,若每日仅搬一个盘子,则当盘子全数搬运完毕之时,此塔将毁损,而也就是世界末日来临之时。


  其实,问题抽离出来很简单,就是有三个柱子A、B、C依次排列,最初的时候A柱子上面有很多圆盘,下面的盘总是比上面的盘大,而我们的最终目标是把所有圆盘都移动到C上面去,并且在移动的过程中遵守两个条件:

  1. 一次只能移动一个盘

  2. 大盘总是在小盘下面


  问题抽离出来了,挺简单的,我们再把问题用C/C++里面的一些术语翻译一下:

  我们有三个等大小的数组A、B、C,最初的时候A数组里面从大到小依次存放着数字,我们需要将数字全部移到C数组里面去,移动过程中遵守两个条件:

  1. 一次只能移动一个数字

  2. 每个数组里面前面的数字总是比后面的数字大。


  问题理清楚了,现在开始就是来分析问题,寻找解决思路(以下过程是我自己解决问题时的思路流程,可能有些是没有必要的,各位看官们不要太较真哈):

  T(n):n个数字从A完全移动到C所需要的次数。

  1. 我的第一感觉是首先寻找移动的规律,那么我们就从简单的入手,经过手动推算T(0) = 0, T(1) = 2, T(2) = 8, T(3) = 26,如果觉得还不能从这里面看出规律的话,那么可以再把T(4) = 80统计出来。从上面我们可以得出T(n) = 3 * T(n-1) + 2。

  2. 有了总和公式之后,其实对我们的解决思路并没有太大的帮助,不过也算是解题过程中一种额外的收获吧。在手动推算的过程中,我们可以发现当只有两个数字的时候,移动的流程是固定的,而当有多个数字的时候,我们把所有数字看成两组,那么这两组数字的移动流程也是固定的。

  3. 也就是说我们可以使用递归来解决我们的问题,这里我是把所有数字看成两组,因为T(2) = 8,每一层的流程不长不短,比较容易实现。

  4. 确定了使用递归,并且将所有数字看成两组来进行递归,那么我们就需要在逻辑上来确定流程。当每一层递归在进行的时候,我们均把操作的对象看做是两个部分,若当前需要操作的数字为m个,那么第一个部分就是前m-1个数字,第二个部分就是第m个数字。当我们在对第一部分操作的时候,可直接递归移动。

  5. 我们有A、B、C三个数组,那么我们的操作就只会有四中操作,A->B、B->A、B->C、C->B,针对于每一个操作我们都是以4中所说的两个部分进行移动的。如:A->B时,A->B的流程是:

    5.1 第一部分(A)->B

    5.2 第一部分(B)->C

    5.3 第二部分(A)->B

    5.4 第一部分(C)->B

而我们会在执行这整套流程之前首先检查传入的A数组是否只有一个数字,若有则不执行流程,直接移动。否则,流程中的每一步都会递归调用,并且将递归调用所想要移动的数组和移动的方向告诉下层的函数。

  6. 在最上层,也就是我们的main函数里面,则直接将数组看成一个部分,我们需要A->B, B->C执行这两个流程就可以了。

以下是我的代码:


#include <iostream>
using namespace std;


#define Array_Size 10
typedef unsigned long long UInt64;


#define LAST_A A.m_array[A.m_actualnumbercnt]
#define LAST_B B.m_array[B.m_actualnumbercnt]
#define LAST_C C.m_array[C.m_actualnumbercnt]


enum Action
{
No_Action, 
A_To_B, 
B_To_A, 
B_To_C,
C_To_B
};


int A[Array_Size];
int B[Array_Size];
int C[Array_Size];


int Initialize()
{
int ret = 0;
for (int i = 0; i < Array_Size; i++)
{
A[i] = Array_Size - i - 1;
B[i] = -1;
C[i] = -1;
}
return ret;
}


struct Array
{
int * m_array;
int m_actualnumbercnt;
int m_arraysize;


Array()
{
m_array = 0;
m_actualnumbercnt = 0;
m_arraysize = Array_Size;
}
};


void Pop_And_Push(Array &X, Array &Y)
{
if (X.m_actualnumbercnt > 0)
{
Y.m_array[Y.m_actualnumbercnt] = X.m_array[X.m_actualnumbercnt - 1];
Y.m_actualnumbercnt++;
X.m_array[X.m_actualnumbercnt - 1] = -1;
X.m_actualnumbercnt--;
}
}


// 递归
int TowerOfHanoi_Recursive(Array &A, Array &B, Array &C, UInt64 &counter, Action this_action)
{
// 通过条件判断,判断出当前可以移动的数字有哪些,再通过其他条件进行排除,最终剩下一个可行性移动方案。
int ret = 0;
int action[4] = {0};
switch(this_action)
{
case A_To_B :
{
if (A.m_actualnumbercnt > 1)
{
ret = A.m_actualnumbercnt;
int movcnt = 0;
Array sub_A = A;
sub_A.m_array++;
sub_A.m_actualnumbercnt--;
Array sub_B = B;
sub_B.m_array += B.m_actualnumbercnt;
sub_B.m_actualnumbercnt = 0;
Array sub_C = C;
sub_C.m_array += C.m_actualnumbercnt;
sub_C.m_actualnumbercnt = 0;
movcnt = TowerOfHanoi_Recursive(sub_A, sub_B, C, counter, A_To_B);
B.m_actualnumbercnt += movcnt;
A.m_actualnumbercnt -= movcnt;
movcnt = TowerOfHanoi_Recursive(A, sub_B, sub_C, counter, B_To_C);
B.m_actualnumbercnt -= movcnt;
C.m_actualnumbercnt += movcnt;
movcnt = TowerOfHanoi_Recursive(A, sub_B, C, counter, A_To_B);
B.m_actualnumbercnt += movcnt;
movcnt = TowerOfHanoi_Recursive(A, sub_B, sub_C, counter, C_To_B);
B.m_actualnumbercnt += movcnt;
C.m_actualnumbercnt -= movcnt;
}
else
{
Pop_And_Push(A, B);
counter++;
ret = 1;
}
break;
}
case B_To_A :
{
if (B.m_actualnumbercnt > 1)
{
ret = B.m_actualnumbercnt;
int movcnt = 0;
Array sub_A = A;
sub_A.m_array += A.m_actualnumbercnt;
sub_A.m_actualnumbercnt = 0;
Array sub_B = B;
sub_B.m_array++;
sub_B.m_actualnumbercnt--;
Array sub_C = C;
sub_C.m_array += C.m_actualnumbercnt;
sub_C.m_actualnumbercnt = 0;
movcnt = TowerOfHanoi_Recursive(A, sub_B, sub_C, counter, B_To_C);
B.m_actualnumbercnt -= movcnt;
C.m_actualnumbercnt += movcnt;
movcnt = TowerOfHanoi_Recursive(sub_A, B, C, counter, B_To_A);
A.m_actualnumbercnt += movcnt;
movcnt = TowerOfHanoi_Recursive(A, sub_B, sub_C, counter, C_To_B);
B.m_actualnumbercnt += movcnt;
C.m_actualnumbercnt -= movcnt;
movcnt = TowerOfHanoi_Recursive(sub_A, sub_B, C, counter, B_To_A);
A.m_actualnumbercnt += movcnt;
B.m_actualnumbercnt -= movcnt;
}
else
{
Pop_And_Push(B, A);
counter++;
ret = 1;
}
break;
}
case B_To_C :
{
if (B.m_actualnumbercnt > 1)
{
ret = B.m_actualnumbercnt;
int movcnt = 0;
Array sub_A = A;
sub_A.m_array += A.m_actualnumbercnt;
sub_A.m_actualnumbercnt = 0;
Array sub_B = B;
sub_B.m_array++;
sub_B.m_actualnumbercnt--;
Array sub_C = C;
sub_C.m_array += C.m_actualnumbercnt;
sub_C.m_actualnumbercnt = 0;
movcnt = TowerOfHanoi_Recursive(sub_A, sub_B, C, counter, B_To_A);
A.m_actualnumbercnt += movcnt;
B.m_actualnumbercnt -= movcnt;
movcnt = TowerOfHanoi_Recursive(A, B, sub_C, counter, B_To_C);
C.m_actualnumbercnt += movcnt;
movcnt = TowerOfHanoi_Recursive(sub_A, sub_B, C, counter, A_To_B);
B.m_actualnumbercnt += movcnt;
A.m_actualnumbercnt -= movcnt;
movcnt = TowerOfHanoi_Recursive(A, sub_B, sub_C, counter, B_To_C);
C.m_actualnumbercnt += movcnt;
B.m_actualnumbercnt -= movcnt;
}
else
{
Pop_And_Push(B, C);
counter++;
ret = 1;
}
break;
}
case C_To_B :
{
if (C.m_actualnumbercnt > 1)
{
ret = C.m_actualnumbercnt;
int movcnt = 0;
Array sub_A = A;
sub_A.m_array += A.m_actualnumbercnt;
sub_A.m_actualnumbercnt = 0;
Array sub_B = B;
sub_B.m_array += B.m_actualnumbercnt;
sub_B.m_actualnumbercnt = 0;
Array sub_C = C;
sub_C.m_array++;
sub_C.m_actualnumbercnt--;
movcnt = TowerOfHanoi_Recursive(A, sub_B, sub_C, counter, C_To_B);
B.m_actualnumbercnt += movcnt;
C.m_actualnumbercnt -= movcnt;
movcnt = TowerOfHanoi_Recursive(sub_A, sub_B, C, counter, B_To_A);
A.m_actualnumbercnt += movcnt;
B.m_actualnumbercnt -= movcnt;
movcnt = TowerOfHanoi_Recursive(A, sub_B, C, counter, C_To_B);
B.m_actualnumbercnt += movcnt;
movcnt = TowerOfHanoi_Recursive(sub_A, sub_B, C, counter, A_To_B);
B.m_actualnumbercnt += movcnt;
A.m_actualnumbercnt -= movcnt;
}
else
{
Pop_And_Push(C, B);
counter++;
ret = 1;
}
break;
}
}
return ret;
}


int main()
{
int ret = 0;
UInt64 counter = 0;
ret = Initialize();
Array a_arr;
Array b_arr;
Array c_arr;
a_arr.m_array = A;
a_arr.m_arraysize = Array_Size;
a_arr.m_actualnumbercnt = Array_Size;
b_arr.m_array = B;
b_arr.m_arraysize = Array_Size;
b_arr.m_actualnumbercnt = 0;
c_arr.m_array = C;
c_arr.m_arraysize = Array_Size;
c_arr.m_actualnumbercnt = 0;
ret = TowerOfHanoi_Recursive(a_arr, b_arr, c_arr, counter, A_To_B);
ret = TowerOfHanoi_Recursive(a_arr, b_arr, c_arr, counter, B_To_C);


cout << "A B C\n";
for (int i = 0; i < Array_Size; i++)
{
cout << A[i] << "" << B[i] << " " << C[i] << endl;
}
cout << "counter : " << counter << endl;
system("pause");
return ret;
}

  

0 0