所以我必须编写这个算法(这个版本不需要在骑士开始的同一个地方结束),我让它工作,但它太慢了。对于size = 8,它适用于起始位置x = 0和y = 0,但如果我尝试将x和y操作为例如2和4,则它在几分钟后不会结束。有人可以帮忙吗?
#include <stdio.h>
#define size 8
int ruch_x[]={ -1, 1, -2, 2, -2, 2, -1, 1}; //arrays of possible knight moves, for example 2nd move is [1,2]//
int ruch_y[]={ 2, 2, 1, 1, -1, -1, -2, -2};
int done(int szach[][size])
{
for(int i=0;i<size;i++)
{
for(int j=0;j<size;j++)
{
if(szach[i][j]==0)
return 0;
}
}
return 1;
}
//licz - variable for counting knights moves//
void konik(int szach[][size], int x, int y, int licz)
{
szach[x][y]=licz;
if(licz<size*size){
for(int i=0;i<=7;i++){ //loop that checks every possible knight move//
if(szach[x+ruch_x[i]][y+ruch_y[i]]==0&&x+ruch_x[i]>=0&&x+ruch_x[i]<size&&y+ruch_y[i]>=0&&y+ruch_y[i]<size)
// checking if candidat was already visited and if it's not outside of the board//
{
konik(szach, x+ruch_x[i], y+ruch_y[i], licz+1);}}}
if(done(szach)==1) return; //checking if whole board is filled with numbers, if yes then skip zeroing current move//
szach[x][y]=0;
}
int main()
{
int i, j, x,y;
printf("set x\n");
scanf("%d", &x);
printf("set y\n");
scanf("%d", &y);
int szach[size][size];
for(i=0;i<size;i++) { //zeroing array//
for(j=0;j<size; j++) {
szach[i][j]=0; }}
konik(szach, x, y, 1);
for(int i=0;i<size;i++) {
for(int j=0;j<size; j++) {
printf("%d\t",szach[j][i]); }
printf("\n\n");}
printf("\n");
return 0;
}
答案 0 :(得分:1)
简单强暴可能是一个坏主意,因为对于8x8电路板,可能的序列数量可能会超过10 ^ 50。
关于维基百科的Knight's tour文章提供了关于这个问题的正确信息,我建议从那里开始。
查找汉密尔顿路径的最着名的启发式方法之一是:从任何节点u
按照图表中的度数按非递减顺序排列邻居。让我们说从u
开始,骑士可以移动到p
和q
(即u
有两个邻居),然后在你的递归中考虑最初p
是否有比q
更少的可用邻居。这通常会导致显着的优化,特别是如果图表中有很多汉密尔顿路径,就像这种情况一样。
关于你的代码。您不需要每次都调用done()。如果在任何时候licz >= size*size
,那么您就知道您找到了答案。例如,您可以存储全局boolean done
。这应该有所帮助,但在所有情况下都无济于事。
P.S。如果您的项目需要任何单一解决方案,我建议存储单个Hamilton 周期,对于任何x,y
,只需简单地移动序列即可获得有效的解决方案。
答案 1 :(得分:0)
这绝不是一个答案,只是一个可能有用的想法。
我记得,对于某些尺寸,简单的螺旋图案将填充电路板的外边缘,并将问题简化为更简单的问题,size
缩小4。
您可以使用此提示来简化您的问题。例如,填充8x3和8x5板而不是8x8板(您必须更新算法以寻找合适的结束位置)。
答案 2 :(得分:0)
ile的建议似乎很好。当我实施时只考虑graph中最低度(可能从位置移动的数量)的候选者(近似为四角中最近的一个),找到起始位置 x = 2 和 y = 4 的解决方案的运行时间从10个半小时减少到1分15秒。计划的变化是:
// arrays of possible knight moves, for example 2nd move is [1,2]
// rearranged so that adjacent moves differ by 45 angular degrees
int ruch_x[]={ 2, 1, -1, -2, -2, -1, 1, 2};
int ruch_y[]={ 1, 2, 2, 1, -1, -2, -2, -1};
#include <stdlib.h>
//licz - variable for counting knights moves//
void konik(int szach[][size], int x, int y, int licz)
{
szach[x][y]=licz;
if (licz<size*size)
{ static char firstmove[2][2][2] = { 1, 0, 6, 7, 2, 3, 5, 4 };
int m = firstmove[x<size/2][y<size/2][abs(size-1-x*2)<abs(size-1-y*2)];
for (int s=0; s<=7; s++) //loop that checks every possible knight move//
{ static int ply[8] = { 0, -1, 1, -2, 2, -3, 3, -4 };
int i = m+ply[s]; // firstmove towards corner, then back and forth
if (i < 0) i += 8;
else
if (i > 7) i -= 8;
// checking if candidate ...
if (x+ruch_x[i]>=0&&x+ruch_x[i]<size // not outside of the board
&& y+ruch_y[i]>=0&&y+ruch_y[i]<size
&& szach[x+ruch_x[i]][y+ruch_y[i]]==0 // not already visited
)
konik(szach, x+ruch_x[i], y+ruch_y[i], licz+1);
}
}
if (done(szach)==1) return; //checking if whole board is filled with numbers
//if yes then skip zeroing current move//
szach[x][y]=0;
}
顺便说一下,原始程序的行为没有严格定义,因为在szach[x+ruch_x[i]][y+ruch_y[i]]
,x+ruch_x[i]
不在板阵列之外的检查之前检查了y+ruch_y[i]
。