题目
Description
在一个5 * 6的棋盘中的某个位置有一只马,如果它走29步正好经过除起点外的其他位置各一次,这样一种走法则称马的周游路线,试设计一个算法,从给定的起点出发,找出它的一条周游路线。
为了便于表示一个棋盘,我们按照从上到下,从左到右对棋盘的方格编号,如下所示:
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
25 26 27 28 29 30
马的走法是“日”字形路线,例如当马在位置 15 的时候,它可以到达 2 、 4 、 7 、 11 、 19 、 23 、 26 和 28 。但是规定马是不能跳出棋盘外的,例如从位置 1 只能到达 9 和 14 。Input
输入有若干行。每行一个整数N(1<=N<=30),表示马的起点。最后一行用-1表示结束,不用处理。
Output
对输入的每一个起点,求一条周游线路。对应地输出一行,有30个整数,从起点开始按顺序给出马每次经过的棋盘方格的编号。相邻的数字用一个空格分开。
这一题用dfs基本上可以通过,关键是马所走方向的顺序会影响到ac时间。对于马在目前位置可以走到的下一个位置,用一个vector数组保存,避免每次都要计算和判断
这样基本0.04s可以ac。
递归版本
int walk[8][2] = {{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2}};
vector<int> walkable[30];
bool visit[30];
bool finish = false;
int route[30];
bool walk_around(int k,int ini_position)
{
if(k == 30)
{
finish = true;
return true;
}
else
{
for(int i=0;i<walkable[ini_position].size();++i)
{
int new_position = walkable[ini_position][i];
if(!visit[new_position])
{
visit[new_position] = true;
route[k]=(new_position);
walk_around(++k,new_position);
if(finish)
return true;
--k;
visit[new_position] = false;
}
}
}
return false;
}
非递归版本
struct Horse { int position; int k; Horse(int p,int n):position(p),k(n){}; Horse(){}; }; Horse walk_around_dfs(int ini_position) { Horse start(ini_position,1); Horse dfs[500]; int top = -1; dfs[++top]= start; while(top!=499) { Horse current = dfs[top--]; visit[current.position] = true; route[current.k-1] = current.position; bool flag = false; if(current.k == 30) return current; else { for(int i = 0 ;i<walkable[current.position].size();++i) { int new_position = walkable[current.position][i]; if(!visit[new_position]) { Horse new_horse = current; new_horse.position = new_position; new_horse.k = current.k+1; flag = true; dfs[++top]= new_horse; } } if(!flag) { visit[current.position] = false; for(int i = current.k-1;i>=dfs[top].k-1;--i) { visit[route[i]] = false; } } } } return Horse(-1,-1); }
这里要注意的是由于消除了递归所以ac的时间要比上面那一题少。这里说一个问题,开始时是使用STL中的stack来实现,回溯的结果发现时间大大超出了限制,后来改用的静态数组模拟栈,轻松过了。由于STL中的stack是采用deque实现的。虽说插入删除的时间也是O(1),但是STL中的stack是用频繁进行指针合法性检查,而且一旦内存空间不够用了,就会动态开辟空间,然后对原来的数据进行拷贝,这就消耗了大量的时间了。