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;
}