2020-12-13

屯江ing發表於2020-12-13

關於馬走日

馬在中國象棋以日字形規則移動。

給定n*m大小的棋盤,以及馬的初始位置(x,y),要求不能重複經過棋盤上的同一個點,計算馬可以有多少途徑遍歷棋盤上的所有點。

對於我來說,最容易想到的是廣搜
對於每一步來說都有8種走法,能走下去的繼續遍歷,走不下去的終止這一分支的計算,然後如果發現走滿棋盤令cnt++
程式碼如下

#include<stdio.h>
int m[8][2] = {{1,2},{-1,2},{1,-2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};
int num[8][8];
int sum[8][8];
int temp,cnt=0,m1,n1;

void bfs(int i,int j,int n){
	sum[i][j]=n;
	if(n!=m1*n1){
		for(int k=0;k<8;k++){
			int ki=i+m[k][0];
			int kj=j+m[k][1];
			if(ki>=0&&ki<m1&&kj>=0&&kj<n1&&(num[ki][kj])==0){
				num[ki][kj]=1;
				bfs(ki,kj,n+1);//走下一步
				num[ki][kj]=0;//清除這一步
			}
		}
	}
	else{
		cnt++;//走滿棋盤令cnt++
	}	
}

int main(void){
	scanf("%d %d",&m1,&n1);
	num[0][0]=1;
	bfs(0,0,1);	
	printf("%d",cnt);
	return 0;
} 

但是這樣並不能輸出每一種路徑的具體走法,所以我們可以用dfs+回溯的方式輸出每一種路徑

#include <stdio.h>
#include<time.h>
#define N 8
#define NN 64
int main() {
	int r_inc[N] = {2,1,-1,-2,-2,-1,1,2};
	int c_inc[N] = {1,2,2,1,-1,-2,-2,-1};
	int board[N][N],step[NN],row[NN],col[NN];
	int m,n,r,c,k,cnt=0;
	printf("請輸入棋盤的長和寬\n") ; 
	scanf("%d %d",&m,&n);
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			board[i][j]=0;
		}
	}//初始化 
	k=0;
	row[0]=0;
	col[0]=0;
	step[0]=0;
	board[0][0]=1;
	while(k>=0){    //徹底走不了k會為-1,然後程式結束 
		if(k==m*n-1){ //如果步數走滿則輸出 
			printf("\n[%d]\n",++cnt);
			for(int i=0;i<m;i++){
				for(int j=0;j<n;j++){
					printf("%3d",board[i][j]);
				}
				printf("\n");
			}
			board[row[k]][col[k]] = 0;
			k--;
		//滿足條件輸出並回退一步
		}else if(step[k]==8){
			board[row[k]][col[k]] = 0;
			k--;//周圍八步都走不了,回退一步
		}else{
			r=row[k]+r_inc[step[k]];
			c=col[k]+c_inc[step[k]];//在第k步的第step[k]個走法 
			step[k]++;//記錄這個走法,如果到8則說明無法繼續 
			if(0<=r&&r<m&&0<=c&&c<n&&board[r][c]==0){
				k++;
				row[k]=r;
				col[k]=c;
				step[k]=0;
				board[r][c]=k+1;//這步能走令步數加1,並記錄這個點是第幾步 
			}
		}
	}
	printf("\n在%d*%d的棋盤上共有%d個解,",m,n,cnt);
	return 0;
}