了解了八皇后問題之后我們再來看一下大同小異的馬走日問題。
問題描述:在n*m的棋盤中,馬只能走"日"字。馬從位置(x,y)出發,把棋盤的每一格都走一次且只走一次。找出所有路徑。
我們以5*4為例,還是將每個格子都標上數字。每個數字都是兩位,十位數字表示該格子所在的行,而個位數字表示該格子所在的列。
這個問題同樣是兩個限制條件:1.每一個格子都走,且每個格子只走一次。2.必須走日字
那么什么情況算是走了日字呢?有什么規律嗎?
1.左下右上橫日字跳法(起始方格與終止方格數字之差為8)
2.左上右下橫日字跳法(起始方格與終止方格數字之差為12)
3.左下右上豎日字跳法(起始方格與終止方格數字之差為19)
4.左上右下豎日字跳法(起始方格與終止方格數字之差為21)
限制條件找到了,我們還是找“馬”的存儲結構,這里我們依然選擇一維數組:因為每個格子只能走一次,所以也符合一維數組的存儲特性,即一個索引對應一個元素。
python實現:
while True: arr1 = [] n = int(input("棋盤行數:")) #輸入行數 m = int(input("棋盤列數:")) #輸入列數 xx = int(input("起始行標:")) #輸入起始行標號 yy = int(input("起始列標:")) #輸入起始列標號 for x in range(n): for y in range(m): a = 10*x+y #通過行列轉換成方格中的數字 arr1.append(a) num = 0 def horse(arr,finish_line=1): arr[0] = xx*10+yy #通過起始位置的行列標號轉換成起始位置方格中的數字 flag = True if finish_line == len(arr): global num num += 1 print("第%s種走法:" %num) for i in arr: #將方格中的元素轉化為下標的形式輸出 mm = str(int(i/10)) nn = str(int(i%10)) print("("+mm+","+nn+")") # print(arr) return 0 for stand in arr1: #保證馬一直在棋盤范圍內活動 arr[finish_line] = stand # print(arr) if finish_line >= 1: #從初始位置的下一個位置判斷是否與上一個位置成日字 if abs(arr[finish_line] - arr[finish_line - 1]) != 8 and abs(arr[finish_line] - arr[finish_line - 1]) != 12 and abs(arr[finish_line] - arr[finish_line - 1]) != 19 and abs(arr[finish_line] - arr[finish_line - 1]) != 21: flag = False else: flag = True for line in range(finish_line): if arr[finish_line] == arr[line]: #判斷當前位置之前是否被走過 flag = False if flag == True: horse(arr,finish_line+1) if __name__ == '__main__': horse([None]*n*m) print(" 一共%s種走法" %num)
JAVA實現:
import java.util.Scanner; import java.util.Arrays; public class horse { public static int num=0; // public static int []arr1 = new int[20]; public static void main(String[] args) { Scanner sc = new Scanner(System.in); //初始化的輸入操作 System.out.println("棋盤高:"); int height = sc.nextInt(); System.out.println("棋盤寬:"); int width = sc.nextInt(); System.out.println("起始橫坐標:"); int startx = sc.nextInt(); System.out.println("起始縱坐標:"); int starty = sc.nextInt(); int []arr = new int[height*width]; int []arr1 = new int[height*width]; //arr1列表用來存放所有格子,同時保證了出界的問題 int i=0; for(int x=0; x<height; x++){ for(int y=0; y<width;y++){ arr1[i++]=10*x+y; } } System.out.println(Arrays.toString(arr1)); arr[0] = 10*startx+starty; int finish_index = 1; int node_num = height*width; horse_ri(arr,arr1,finish_index); System.out.printf("共%d種走法",num); } static void horse_ri(int arr[],int arr1[],int finish_index){ boolean flag=true; if(finish_index==arr.length){ num++; System.out.printf("第%d種走法",num); System.out.println(Arrays.toString(arr)); return; } for(int ind=1;ind<arr1.length; ind++){ arr[finish_index]=arr1[ind]; flag = true;
//不是日字的情況 if((Math.abs(arr[finish_index]-arr[finish_index-1])!=8)&&(Math.abs(arr[finish_index]-arr[finish_index-1])!=12)&&(Math.abs(arr[finish_index]-arr[finish_index-1])!=19)&&(Math.abs(arr[finish_index]-arr[finish_index-1])!=21)){ flag = false; }
//之前走過的格子 for(int index=0;index<finish_index;index++){ if(arr[finish_index]==arr[index]){ flag = false; } } if(flag==true){ horse_ri(arr,arr1,finish_index+1); } } } }