2008年12月1日 星期一
Knight's Tour using non-recursive programing
解法:
騎士的走法,基本上可以使用遞迴來解決,但是純綷的遞迴在維度大時相當沒有效率,一個聰明的解法由J.C. Warnsdorff在1823年提出,簡單的說,先將最難的位置走完,接下來的路就寬廣了,騎士所要走的下一步,「為下一步再選擇時,所能走的步數最少 的一步。」,使用這個方法,在不使用遞迴的情況下,可以有較高的機率找出走法(找不到走法的機會也是有的)。
演算法:
for (step = 1; step < 總格數 ; step++)
{
測試下一步可以走的八個方向,並記錄下步可走的格數。
if ( 下步可走格數 == 0 )
{
return 0;
}
else if ( 可走格數 == 1 )
{
下一步只有一種可能
}
else
{
重複 if 內容找出下一步的下一步可走的最少格來走,藉此提升行走效率,
如果計算到最少格有相同者,則選第一順位來走。
}
檢查stack,找出最少出路的那一步,並replace騎士的位置,
再下一個for loop則由此新位置來走。
}
//----------------------------------------------------------------------------------------------
//若是8*8的棋盤,其中 (5,4) 這點無解
程式碼:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define col_size 8
#define row_size 8
typedef struct NextMove
{
int i;
int j;
}NextMove;
void clear();
int knight(int,int);
int checker[row_size+4][col_size+4];
int step=0;
int ans=0;
// Knight's directions in X-axis and Y-axis.
const int horizontal[8]={ 2, 1,-1,-2,-2,-1, 1, 2};
const int vertical[8]={-1,-2,-2,-1, 1, 2, 2, 1};
NextMove next[row_size];
int main()
{
time_t ticks1,ticks2;
int i,j,p,t;
clear();
ticks1 = time(NULL);
for(p=2;p<row_size+2;p++)
for(t=2;t<col_size+2;t++)
{
clear();
if(knight(p,t)!=0)
{
printf("\nAns : %d\tStep : %d\n",++ans,step);
for(i=2;i<row_size+2;i++)
{
for(j=2;j<col_size+2;j++)
printf("%3d",checker[i][j]);
printf("\n");
}
}
}
ticks2 = time(NULL);
printf("\nStart time : %.24s\r\n",ctime(&ticks1));
printf(" End time : %.24s\r\n",ctime(&ticks2));
system("PAUSE");
return 0;
}
// To avoid that the knight goes out of range.
void clear()
{
int i,j;
for(i=0;i<row_size+4;i++)
for(j=0;j<col_size+4;j++)
if(i<2||i>row_size+1||j<2||j>col_size+1)
checker[i][j]=-1;
else
checker[i][j]=0;
step=0;
}
// Find the path.
int knight(int i,int j)
{
int p,t,k,temp,count;
int temp_i,temp_j,min_way,second_way[row_size];
// Clear the next step stack
for(p=0;p<8;p++)
{
next[p].i=0;
next[p].j=0;
}
checker[i][j]=1;
for(p=1;p<row_size*col_size;p++)
{
// Clear the number of ways of each next step
for(t=0;t<8;t++)
second_way[t]=0;
// Reset index "count"
count=0;
// Try the eight directions
for(k=0;k<8;k++)
{
temp_i=i+vertical[k];
temp_j=j+horizontal[k];
// If the direction is passable then set up the knight,
// and ways counting++
if(checker[temp_i][temp_j]==0)
{
next[count].i=temp_i;
next[count++].j=temp_j;
}
}
// After trying the eight directions
// If no ways can move
if(count==0)
return 0;
// If just one way can move then thw way is the smallest-step way
else if(count==1)
// Thw direction was pushed in next[0]
min_way=0;
// Otherwise find the smallest ways of the next ways,
// if we got the same ways then choose the first one.
else
{
// Find the ways of each next-step way
for(t=0;t<count;t++)
// Try the eight directions like before
for(k=0;k<8;k++)
{
temp_i=next[t].i+vertical[k];
temp_j=next[t].j+horizontal[k];
if(checker[temp_i][temp_j]==0)
second_way[t]++;
}
temp=second_way[0];
min_way=0;
// Search for the smallest ways of each next-step way
for(t=1;t<count;t++)
if(second_way[t]<temp)
{
temp=second_way[t];
min_way=t;
}
}
// Find out the smallest ways of the next step
i=next[min_way].i;
j=next[min_way].j;
checker[i][j]=p+1;
}
step=p;
return 1;
}
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言