唉!!! 上次交作业写错题目了,做了简单的马周游 sicily 1152。补上新的,应该是sicily 1153.为了解决规模太大的问题。加上了优化算法。
// elocution数组在初始化后会记下每个有效位置的下一步有哪些可走位
// 置.elocution[x][0]用下标0记个数。最多8个有效可走位置。
char elocution[ELEM_COUNT][9];
// stamps数组记每个点是否已经走过了。0表示没走过,1表示走过了。
char stamps[ELEM_COUNT];
// track数组记路径的顺序。
char track[ELEM_COUNT];
通过结合stamps数组和elocution数组可以算出下一步的每个点的权重。
(3)详细解题思路
1. 先初始化一张表。这张表记下了棋盘上所有的30个位置的下一步可走的有效位置.
2. 写一个一般的递归调用自己的函数,表示马在走第几步时到了哪个位置,然后求出余下的所有可走位置。
3. 余下的所有位置按照上文提到的权重排序。
4. 对于排序后的可选点数组,按顺序依次用递归函数尝试。
5. 递归函数有三个退出条件。1.下一个要尝试的点已经走过了,2.试完了所有的可选下一步无解。3.走到了最后一步,即得解!
(4)算法描述
初如化上文提到的elocution数组,清空stamps和tracks.从起点开始调用递归函数。
http://ykyi.net zausiu's blog.
(5)程序注释清单
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <csetjmp>
//#include <cassert>
using namespace std;
#define ROW_NUM 8
#define COLUMN_NUM 8
#define ELEM_COUNT ROW_NUM * COLUMN_NUM
jmp_buf jmpbuffer; // 很深的函数递归调用时用longjmp快速退出.
// elocution数组在初始化后会记下每个有效位置的下一步有哪些可走位
// 置.elocution[x][0]用下标0记个数。最多8个有效可走位置。
char elocution[ELEM_COUNT][9];
// stamps数组记每个点是否已经走过了。0表示没走过,1表示走过了。
char stamps[ELEM_COUNT];
struct coordinate // 二维坐标
{
char _x; // start from zero.
char _y;
};
// 作标转序号
char coordinate2serial_num(coordinate co)
{
char num = co._x * COLUMN_NUM + co._y + 1;
return num;
}
// 序号转坐标
coordinate serial_num2coordinate(char sn)
{
coordinate co;
co._x = (sn - 1) / COLUMN_NUM;
co._y = sn - co._x * COLUMN_NUM - 1;
return co;
}
// ((x:1;y:-2),(x:2;y:-1),(x:2;y:1),(x:1;y:2) (x:-1;y:2),(x:-2;y:1),(x:-2;y:-1),(x:-1;y:-2));
char increments[8][2] =
{
1, -2, 2, -1, 2, 1, 1, 2,
-1, 2, -2, 1, -2, -1, -1, -2
};
void next_step(char pos, char steps[]) // 把位置在pos序号的点的每一个下一个可选位置记在数组中。
{
char valid_count = 0;
coordinate co = serial_num2coordinate(pos);
coordinate tmp;
char serial_num;
for ( int i = 0; i < 8; i++ )
{
tmp._x = co._x + increments[i][0];
tmp._y = co._y + increments[i][1];
if ( tmp._x < 0 || tmp._x >= ROW_NUM || tmp._y < 0 || tmp._y >= COLUMN_NUM ) // 保证位置有效
{
continue;
}
serial_num = coordinate2serial_num(tmp);
if ( serial_num >= 1 && serial_num <= ELEM_COUNT )
{
valid_count++;
steps[valid_count] = serial_num;
}
else
{
cerr << "Not expected to reach here.\n";
}
}
steps[0] = valid_count;
}
// 下面的逻辑以每个点的下一步可跳点的数目作为权重排序。
struct pos_weight
{
char _pos;
char _weight;
};
// 又是用递归。这里为了实现快速排序
int partition(pos_weight poses[], int low, int high)
{
pos_weight pivot = poses[low];
while (low < high)
{
while (low < high && pivot._weight < poses[high]._weight)
high--;
poses[low] = poses[high];
while (low < high && pivot._weight >= poses[low]._weight)
low++;
poses[high] = poses[low];
}
poses[low] = pivot;
return low;
}
// 快速排序。
void quick_sort_steps(pos_weight poses[], int low, int high)
{
if ( low < high )
{
int pivot_loc = partition(poses, low, high);
quick_sort_steps(poses, low, pivot_loc-1);
quick_sort_steps(poses, pivot_loc+1, high);
}
}
void rearrage_steps(char poses[], int len) // poese里放置了下一个位置数组。Len是数组长度。
{
char weight, pos, next_step_count;
vector<pos_weight> vec(len);
for ( int i = 0; i < len; i++ ) // 计算权重.
{
weight = 0;
pos = poses[i];
next_step_count = elocution[pos-1][0];
for ( int j = 0; j < next_step_count; j++ )
{
char next_step_pos = elocution[pos-1][j+1];
if ( 0 == stamps[next_step_pos-1] )
{
weight++; // 如果有一下一跳点没走过则权重加1.
}
}
vec[i]._pos = pos;
vec[i]._weight = weight;
}
quick_sort_steps(&vec[0], 0, len-1); // 根据权重排序.
for ( int i = 0; i < len; i++ ) // 把排序后的位置写回原始数组.
{
poses[i] = vec[i]._pos;
}
}
void init_elocution()
{
memset(stamps, 0, sizeof(stamps));
for ( int i = 1; i <= ELEM_COUNT; i++ )
{
next_step(i, elocution[i-1]);
}
}
char track[ELEM_COUNT];
void run_horse(char start_pos, char step_count) // step_count [0 -- 64)
{
// 如果已经经过这点就立即退出函数。
if ( 1 == stamps[start_pos-1] )
{
return;
}
track[step_count] = start_pos;
if ( step_count == COLUMN_NUM * ROW_NUM - 1 ) // 是不是最后一步。
{
for ( int i = 0; i < sizeof(track); i++ )
{
cout << (int)track[i];
if ( i + 1 != sizeof(track) )
{
cout << " ";
}
}
cout << endl;
longjmp(jmpbuffer, 0x1);
return;
}
// 记下已经走了这一步。
stamps[start_pos-1] = 1; rearrage_steps(elocution[start_pos-1]+1, elocution[start_pos-1][0]);
for ( int i = 0; i < elocution[start_pos-1][0]; i++ )
{
run_horse(elocution[start_pos-1][i+1], step_count+1);
}
stamps[start_pos-1] = 0; // 试完了所有可走步.退出这个函数.重置这个位置为没有走过。
}
int main(int argc, char* argv[])
{
int pos;
vector<int> vec;
while(true)
{
cin >> pos;
if (pos==-1)
{
break;
}
vec.push_back(pos);
}
for ( int i = 0; i < vec.size(); i++ )
{
if(setjmp(jmpbuffer) == 0) // 为了很深的递归函数快速回退到这里。
{
init_elocution();
memset(track, 0, sizeof(track));
memset(stamps, 0, sizeof(stamps));
run_horse(vec[i], 0);
}
}
return 0;
}